[Cocoa] Support font collections
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 23 Jan 2018 02:09:22 +0000 (02:09 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 23 Jan 2018 02:09:22 +0000 (02:09 +0000)
https://bugs.webkit.org/show_bug.cgi?id=181826
<rdar://problem/36455137>

Reviewed by Dean Jackson.

Source/WebCore:

Use the CoreText call CTFontManagerCreateFontDescriptorsFromData() to get all the descriptors inside
the collection file. We select which one by using the fragment identifier at the end of the url linking
to the remote font. For example, to select the 4th font inside a TTC file, the @font-face block would
look like:

@font-face {
    font-family: "MyFont";
    src: url("path/to/font.ttc#4");
}

Note that these numbers are 1-indexed.

The CSS Fonts spec states:
> Fragment identifiers are used to indicate which font to load. If a container format lacks a defined
> fragment identifier scheme, implementations should use a simple 1-based indexing scheme (e.g.
> "font-collection#1" for the first font, "font-collection#2" for the second font).

Not only are TTC font collections supported, but WOFF2 font collections are also supported, which is
increasingly important web standard.

No new tests because I don't have a font collection file with the appropriate license for the
WebKit repository. I tested manually.

* css/CSSFontFaceSource.cpp:
(WebCore::CSSFontFaceSource::load):
* loader/cache/CachedFont.cpp:
(WebCore::CachedFont::calculateIndex const):
(WebCore::CachedFont::ensureCustomFontData):
(WebCore::CachedFont::createCustomFontData):
* loader/cache/CachedFont.h:
* platform/graphics/cairo/FontCustomPlatformData.h:
* platform/graphics/freetype/FontCustomPlatformDataFreeType.cpp:
(WebCore::createFontCustomPlatformData):
* platform/graphics/mac/FontCustomPlatformData.cpp:
(WebCore::createFontCustomPlatformData):
* platform/graphics/mac/FontCustomPlatformData.h:
* platform/graphics/win/FontCustomPlatformData.cpp:
(WebCore::createFontCustomPlatformData):
* platform/graphics/win/FontCustomPlatformData.h:
* platform/graphics/win/FontCustomPlatformDataCairo.cpp:
(WebCore::createFontCustomPlatformData):

Source/WebCore/PAL:

* pal/spi/cocoa/CoreTextSPI.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@227381 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
Source/WebCore/ChangeLog
Source/WebCore/PAL/ChangeLog
Source/WebCore/PAL/pal/spi/cocoa/CoreTextSPI.h
Source/WebCore/css/CSSFontFaceSource.cpp
Source/WebCore/loader/cache/CachedFont.cpp
Source/WebCore/loader/cache/CachedFont.h
Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h
Source/WebCore/platform/graphics/freetype/FontCustomPlatformDataFreeType.cpp
Source/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
Source/WebCore/platform/graphics/mac/FontCustomPlatformData.h
Source/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
Source/WebCore/platform/graphics/win/FontCustomPlatformData.h
Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp

index 62cac5c..7e1f14b 100644 (file)
@@ -1,3 +1,53 @@
+2018-01-22  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [Cocoa] Support font collections
+        https://bugs.webkit.org/show_bug.cgi?id=181826
+        <rdar://problem/36455137>
+
+        Reviewed by Dean Jackson.
+
+        Use the CoreText call CTFontManagerCreateFontDescriptorsFromData() to get all the descriptors inside
+        the collection file. We select which one by using the fragment identifier at the end of the url linking
+        to the remote font. For example, to select the 4th font inside a TTC file, the @font-face block would
+        look like:
+
+        @font-face {
+            font-family: "MyFont";
+            src: url("path/to/font.ttc#4");
+        }
+
+        Note that these numbers are 1-indexed.
+
+        The CSS Fonts spec states:
+        > Fragment identifiers are used to indicate which font to load. If a container format lacks a defined
+        > fragment identifier scheme, implementations should use a simple 1-based indexing scheme (e.g.
+        > "font-collection#1" for the first font, "font-collection#2" for the second font).
+
+        Not only are TTC font collections supported, but WOFF2 font collections are also supported, which is
+        increasingly important web standard.
+
+        No new tests because I don't have a font collection file with the appropriate license for the
+        WebKit repository. I tested manually.
+
+        * css/CSSFontFaceSource.cpp:
+        (WebCore::CSSFontFaceSource::load):
+        * loader/cache/CachedFont.cpp:
+        (WebCore::CachedFont::calculateIndex const):
+        (WebCore::CachedFont::ensureCustomFontData):
+        (WebCore::CachedFont::createCustomFontData):
+        * loader/cache/CachedFont.h:
+        * platform/graphics/cairo/FontCustomPlatformData.h:
+        * platform/graphics/freetype/FontCustomPlatformDataFreeType.cpp:
+        (WebCore::createFontCustomPlatformData):
+        * platform/graphics/mac/FontCustomPlatformData.cpp:
+        (WebCore::createFontCustomPlatformData):
+        * platform/graphics/mac/FontCustomPlatformData.h:
+        * platform/graphics/win/FontCustomPlatformData.cpp:
+        (WebCore::createFontCustomPlatformData):
+        * platform/graphics/win/FontCustomPlatformData.h:
+        * platform/graphics/win/FontCustomPlatformDataCairo.cpp:
+        (WebCore::createFontCustomPlatformData):
+
 2018-01-22  Simon Fraser  <simon.fraser@apple.com>
 
         REGRESSION (r227011): fast/frames/hidpi-position-iframe-on-device-pixel.html times out
index 39d2741..0ac0b41 100644 (file)
@@ -1,3 +1,13 @@
+2018-01-22  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [Cocoa] Support font collections
+        https://bugs.webkit.org/show_bug.cgi?id=181826
+        <rdar://problem/36455137>
+
+        Reviewed by Dean Jackson.
+
+        * pal/spi/cocoa/CoreTextSPI.h:
+
 2018-01-21  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         Add a new feature flag for EXTRA_ZOOM_MODE and reintroduce AdditionalFeatureDefines.h
index 7dcfcde..e7da532 100644 (file)
@@ -84,6 +84,8 @@ CFBitVectorRef CTFontCopyGlyphCoverageForFeature(CTFontRef, CFDictionaryRef feat
 CTFontDescriptorRef CTFontDescriptorCreateWithAttributesAndOptions(CFDictionaryRef attributes, CTFontDescriptorOptions);
 CTFontDescriptorRef CTFontDescriptorCreateLastResort();
 
+CFArrayRef CTFontManagerCreateFontDescriptorsFromData(CFDataRef);
+
 extern const CFStringRef kCTFontCSSWeightAttribute;
 extern const CFStringRef kCTFontCSSWidthAttribute;
 extern const CFStringRef kCTFontDescriptorTextStyleAttribute;
index 9e12dbc..85a4eab 100644 (file)
@@ -159,7 +159,7 @@ void CSSFontFaceSource::load(CSSFontSelector* fontSelector)
                 if (auto otfFont = convertSVGToOTFFont(fontElement))
                     m_generatedOTFBuffer = SharedBuffer::create(WTFMove(otfFont.value()));
                 if (m_generatedOTFBuffer) {
-                    m_inDocumentCustomPlatformData = createFontCustomPlatformData(*m_generatedOTFBuffer);
+                    m_inDocumentCustomPlatformData = createFontCustomPlatformData(*m_generatedOTFBuffer, 0);
                     success = static_cast<bool>(m_inDocumentCustomPlatformData);
                 }
             }
@@ -170,7 +170,7 @@ void CSSFontFaceSource::load(CSSFontSelector* fontSelector)
             bool wrapping;
             RefPtr<SharedBuffer> buffer = SharedBuffer::create(static_cast<const char*>(m_immediateSource->baseAddress()), m_immediateSource->byteLength());
             ASSERT(buffer);
-            m_immediateFontCustomPlatformData = CachedFont::createCustomFontData(*buffer, wrapping);
+            m_immediateFontCustomPlatformData = CachedFont::createCustomFontData(*buffer, 0, wrapping);
             success = static_cast<bool>(m_immediateFontCustomPlatformData);
         } else {
             // We are only interested in whether or not fontForFamily() returns null or not. Luckily, none of
index 13f0b40..2b6815e 100644 (file)
@@ -88,11 +88,27 @@ bool CachedFont::ensureCustomFontData(const AtomicString&)
     return ensureCustomFontData(m_data.get());
 }
 
+unsigned CachedFont::calculateIndex() const
+{
+    auto& url = this->url();
+    if (!url.hasFragmentIdentifier())
+        return 0;
+    const auto& fragment = url.fragmentIdentifier();
+    unsigned result = 0;
+    for (unsigned i = 0; i < fragment.length(); ++i) {
+        UChar c = fragment[i];
+        if (c < '0' || c > '9')
+            return 0;
+        result = result * 10 + (c - '0');
+    }
+    return result;
+}
+
 bool CachedFont::ensureCustomFontData(SharedBuffer* data)
 {
     if (!m_fontCustomPlatformData && !errorOccurred() && !isLoading() && data) {
         bool wrapping;
-        m_fontCustomPlatformData = createCustomFontData(*data, wrapping);
+        m_fontCustomPlatformData = createCustomFontData(*data, calculateIndex(), wrapping);
         m_hasCreatedFontDataWrappingResource = m_fontCustomPlatformData && wrapping;
         if (!m_fontCustomPlatformData)
             setStatus(DecodeError);
@@ -101,7 +117,7 @@ bool CachedFont::ensureCustomFontData(SharedBuffer* data)
     return m_fontCustomPlatformData.get();
 }
 
-std::unique_ptr<FontCustomPlatformData> CachedFont::createCustomFontData(SharedBuffer& bytes, bool& wrapping)
+std::unique_ptr<FontCustomPlatformData> CachedFont::createCustomFontData(SharedBuffer& bytes, unsigned index, bool& wrapping)
 {
     wrapping = true;
 
@@ -113,11 +129,11 @@ std::unique_ptr<FontCustomPlatformData> CachedFont::createCustomFontData(SharedB
             return nullptr;
 
         auto buffer = SharedBuffer::create(WTFMove(convertedFont));
-        return createFontCustomPlatformData(buffer);
+        return createFontCustomPlatformData(buffer, index);
     }
 #endif
 
-    return createFontCustomPlatformData(bytes);
+    return createFontCustomPlatformData(bytes, index);
 }
 
 RefPtr<Font> CachedFont::createFont(const FontDescription& fontDescription, const AtomicString&, bool syntheticBold, bool syntheticItalic, const FontFeatureSettings& fontFaceFeatures, const FontVariantSettings& fontFaceVariantSettings, FontSelectionSpecifiedCapabilities fontFaceCapabilities)
index 015c650..daa3c73 100644 (file)
@@ -52,7 +52,7 @@ public:
     bool stillNeedsLoad() const override { return !m_loadInitiated; }
 
     virtual bool ensureCustomFontData(const AtomicString& remoteURI);
-    static std::unique_ptr<FontCustomPlatformData> createCustomFontData(SharedBuffer&, bool& wrapping);
+    static std::unique_ptr<FontCustomPlatformData> createCustomFontData(SharedBuffer&, unsigned index, bool& wrapping);
     static FontPlatformData platformDataFromCustomData(FontCustomPlatformData&, const FontDescription&, bool bold, bool italic, const FontFeatureSettings&, const FontVariantSettings&, FontSelectionSpecifiedCapabilities);
 
     virtual RefPtr<Font> createFont(const FontDescription&, const AtomicString& remoteURI, bool syntheticBold, bool syntheticItalic, const FontFeatureSettings&, const FontVariantSettings&, FontSelectionSpecifiedCapabilities);
@@ -63,6 +63,8 @@ protected:
     bool ensureCustomFontData(SharedBuffer* data);
 
 private:
+    unsigned calculateIndex() const;
+
     void checkNotify() override;
     bool mayTryReplaceEncodedData() const override;
 
index b168534..adb30e7 100644 (file)
@@ -48,7 +48,7 @@ private:
     cairo_font_face_t* m_fontFace;
 };
 
-std::unique_ptr<FontCustomPlatformData> createFontCustomPlatformData(SharedBuffer&);
+std::unique_ptr<FontCustomPlatformData> createFontCustomPlatformData(SharedBuffer&, unsigned);
 
 } // namespace WebCore
 
index 8107fb1..4c1b16d 100644 (file)
@@ -90,7 +90,7 @@ static bool initializeFreeTypeLibrary(FT_Library& library)
     return true;
 }
 
-std::unique_ptr<FontCustomPlatformData> createFontCustomPlatformData(SharedBuffer& buffer)
+std::unique_ptr<FontCustomPlatformData> createFontCustomPlatformData(SharedBuffer& buffer, unsigned)
 {
     static FT_Library library;
     if (!library && !initializeFreeTypeLibrary(library)) {
index 069a795..e7d410f 100644 (file)
 #include "FontDescription.h"
 #include "FontPlatformData.h"
 #include "SharedBuffer.h"
+#include <CoreFoundation/CoreFoundation.h>
 #include <CoreGraphics/CoreGraphics.h>
 #include <CoreText/CoreText.h>
+#include <pal/spi/cocoa/CoreTextSPI.h>
 
 namespace WebCore {
 
@@ -43,11 +45,27 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(const FontDescription&
     return FontPlatformData(font.get(), size, bold, italic, orientation, widthVariant, fontDescription.textRenderingMode());
 }
 
-std::unique_ptr<FontCustomPlatformData> createFontCustomPlatformData(SharedBuffer& buffer)
+std::unique_ptr<FontCustomPlatformData> createFontCustomPlatformData(SharedBuffer& buffer, unsigned index)
 {
     RetainPtr<CFDataRef> bufferData = buffer.createCFData();
 
-    RetainPtr<CTFontDescriptorRef> fontDescriptor = adoptCF(CTFontManagerCreateFontDescriptorFromData(bufferData.get()));
+    RetainPtr<CTFontDescriptorRef> fontDescriptor;
+#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000)
+    auto array = adoptCF(CTFontManagerCreateFontDescriptorsFromData(bufferData.get()));
+    if (!array)
+        return nullptr;
+    auto length = CFArrayGetCount(array.get());
+    if (length <= 0)
+        return nullptr;
+    if (index > 0)
+        --index;
+    if (index >= static_cast<unsigned>(length))
+        index = 0;
+    fontDescriptor = static_cast<CTFontDescriptorRef>(CFArrayGetValueAtIndex(array.get(), index));
+#else
+    UNUSED_PARAM(index);
+    fontDescriptor = adoptCF(CTFontManagerCreateFontDescriptorFromData(bufferData.get()));
+#endif
     if (!fontDescriptor)
         return nullptr;
 
index 838c414..9cf7618 100644 (file)
@@ -57,7 +57,7 @@ public:
     RetainPtr<CTFontDescriptorRef> m_fontDescriptor;
 };
 
-std::unique_ptr<FontCustomPlatformData> createFontCustomPlatformData(SharedBuffer&);
+std::unique_ptr<FontCustomPlatformData> createFontCustomPlatformData(SharedBuffer&, unsigned index);
 
 }
 
index 7c903b0..c878e42 100644 (file)
@@ -97,7 +97,7 @@ static String createUniqueFontName()
     return fontName;
 }
 
-std::unique_ptr<FontCustomPlatformData> createFontCustomPlatformData(SharedBuffer& buffer)
+std::unique_ptr<FontCustomPlatformData> createFontCustomPlatformData(SharedBuffer& buffer, unsigned)
 {
     String fontName = createUniqueFontName();
     HANDLE fontReference;
index eecb89c..2f1aa16 100644 (file)
@@ -54,7 +54,7 @@ public:
     String m_name;
 };
 
-std::unique_ptr<FontCustomPlatformData> createFontCustomPlatformData(SharedBuffer&);
+std::unique_ptr<FontCustomPlatformData> createFontCustomPlatformData(SharedBuffer&, unsigned);
 
 }
 
index c63feec..0d9a7c3 100644 (file)
@@ -85,7 +85,7 @@ static String createUniqueFontName()
     return fontName;
 }
 
-std::unique_ptr<FontCustomPlatformData> createFontCustomPlatformData(SharedBuffer& buffer)
+std::unique_ptr<FontCustomPlatformData> createFontCustomPlatformData(SharedBuffer& buffer, unsigned)
 {
     String fontName = createUniqueFontName();
     HANDLE fontReference = renameAndActivateFont(buffer, fontName);