Title: [223860] trunk/Source/WebCore
Revision
223860
Author
[email protected]
Date
2017-10-23 15:37:33 -0700 (Mon, 23 Oct 2017)

Log Message

[iOS] DocumentWriter::createDocument can spend ~100ms unnecessarily converting image UTIs to MIME types
https://bugs.webkit.org/show_bug.cgi?id=178618
<rdar://problem/35108852>

Reviewed by Said Abou-Hallawa.

Currently, in setting up a new Document, DocumentWriter::createDocument() always asks whether or not the
Document should be a PDF document by calling MIMETypeRegistry::isPDFMIMEType(), which forces lazy initialization
of every MIME type dictionary (e.g. image types, PDF types, _javascript_ types, etc.). As evidenced by traces,
this can be an expensive operation on certain devices.

This patch implements two optimizations. First, we refactor the initializeSupportedImageMIMETypes() helper to
stop asking for MIMETypeForImageSourceType for each of the supported UTIs. This is because the known MIME types
corresponding to these hard-coded UTI types is a fixed set anyways, so we can simply iterate over a constant
array of MIME types and populate the supported image (and image resource) types. Also, add assertions to ensure
that we keep allowed image MIME types in sync with allowed image UTIs.

The second optimization removes initializeMIMETypeRegistry() altogether in favor of calling just the
initialize*MIMETypes() functions needed to ensure the information required. For instance, getPDFMIMETypes()
currently calls initializeMIMETypeRegistry() if the pdfMIMETypes dictionary doesn't exist, when it really only
needs to ensure that the pdfMIMETypes is initialized, for which initializePDFMIMETypes() is sufficient.

* platform/MIMETypeRegistry.cpp:
(WebCore::initializeSupportedImageMIMETypes):
(WebCore::initializeSupportedJavaScriptMIMETypes):
(WebCore::initializePDFMIMETypes):
(WebCore::initializeSupportedNonImageMimeTypes):
(WebCore::initializeUnsupportedTextMIMETypes):

Move MIME type dictionary creation into initialize*MIMETypes() helpers. Additionally, remove
initializePDFAndPostScriptMIMETypes, which is no longer necessary.

(WebCore::MIMETypeRegistry::isSupportedImageMIMEType):
(WebCore::MIMETypeRegistry::isSupportedImageResourceMIMEType):
(WebCore::MIMETypeRegistry::isSupportedJavaScriptMIMEType):
(WebCore::MIMETypeRegistry::isSupportedNonImageMIMEType):
(WebCore::MIMETypeRegistry::isUnsupportedTextMIMEType):
(WebCore::MIMETypeRegistry::isPDFOrPostScriptMIMEType):

Tweak to check that the type isPDFMIMEType(), or that it's otherwise "application/postscript".

(WebCore::MIMETypeRegistry::isPDFMIMEType):
(WebCore::MIMETypeRegistry::getSupportedImageMIMETypes):
(WebCore::MIMETypeRegistry::getSupportedImageResourceMIMETypes):
(WebCore::MIMETypeRegistry::getSupportedNonImageMIMETypes):
(WebCore::MIMETypeRegistry::getPDFMIMETypes):
(WebCore::MIMETypeRegistry::getUnsupportedTextMIMETypes):

Call only the relevant MIME type initializers when needed.

(WebCore::initializePostScriptMIMETypes): Deleted.
(WebCore::initializeMIMETypeRegistry): Deleted.
(WebCore::MIMETypeRegistry::getPDFAndPostScriptMIMETypes): Deleted.

Remove an unused and unexported function.

* platform/MIMETypeRegistry.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (223859 => 223860)


--- trunk/Source/WebCore/ChangeLog	2017-10-23 22:30:23 UTC (rev 223859)
+++ trunk/Source/WebCore/ChangeLog	2017-10-23 22:37:33 UTC (rev 223860)
@@ -1,3 +1,63 @@
+2017-10-23  Wenson Hsieh  <[email protected]>
+
+        [iOS] DocumentWriter::createDocument can spend ~100ms unnecessarily converting image UTIs to MIME types
+        https://bugs.webkit.org/show_bug.cgi?id=178618
+        <rdar://problem/35108852>
+
+        Reviewed by Said Abou-Hallawa.
+
+        Currently, in setting up a new Document, DocumentWriter::createDocument() always asks whether or not the
+        Document should be a PDF document by calling MIMETypeRegistry::isPDFMIMEType(), which forces lazy initialization
+        of every MIME type dictionary (e.g. image types, PDF types, _javascript_ types, etc.). As evidenced by traces,
+        this can be an expensive operation on certain devices.
+
+        This patch implements two optimizations. First, we refactor the initializeSupportedImageMIMETypes() helper to
+        stop asking for MIMETypeForImageSourceType for each of the supported UTIs. This is because the known MIME types
+        corresponding to these hard-coded UTI types is a fixed set anyways, so we can simply iterate over a constant
+        array of MIME types and populate the supported image (and image resource) types. Also, add assertions to ensure
+        that we keep allowed image MIME types in sync with allowed image UTIs.
+
+        The second optimization removes initializeMIMETypeRegistry() altogether in favor of calling just the
+        initialize*MIMETypes() functions needed to ensure the information required. For instance, getPDFMIMETypes()
+        currently calls initializeMIMETypeRegistry() if the pdfMIMETypes dictionary doesn't exist, when it really only
+        needs to ensure that the pdfMIMETypes is initialized, for which initializePDFMIMETypes() is sufficient.
+
+        * platform/MIMETypeRegistry.cpp:
+        (WebCore::initializeSupportedImageMIMETypes):
+        (WebCore::initializeSupportedJavaScriptMIMETypes):
+        (WebCore::initializePDFMIMETypes):
+        (WebCore::initializeSupportedNonImageMimeTypes):
+        (WebCore::initializeUnsupportedTextMIMETypes):
+
+        Move MIME type dictionary creation into initialize*MIMETypes() helpers. Additionally, remove
+        initializePDFAndPostScriptMIMETypes, which is no longer necessary.
+
+        (WebCore::MIMETypeRegistry::isSupportedImageMIMEType):
+        (WebCore::MIMETypeRegistry::isSupportedImageResourceMIMEType):
+        (WebCore::MIMETypeRegistry::isSupportedJavaScriptMIMEType):
+        (WebCore::MIMETypeRegistry::isSupportedNonImageMIMEType):
+        (WebCore::MIMETypeRegistry::isUnsupportedTextMIMEType):
+        (WebCore::MIMETypeRegistry::isPDFOrPostScriptMIMEType):
+
+        Tweak to check that the type isPDFMIMEType(), or that it's otherwise "application/postscript".
+
+        (WebCore::MIMETypeRegistry::isPDFMIMEType):
+        (WebCore::MIMETypeRegistry::getSupportedImageMIMETypes):
+        (WebCore::MIMETypeRegistry::getSupportedImageResourceMIMETypes):
+        (WebCore::MIMETypeRegistry::getSupportedNonImageMIMETypes):
+        (WebCore::MIMETypeRegistry::getPDFMIMETypes):
+        (WebCore::MIMETypeRegistry::getUnsupportedTextMIMETypes):
+
+        Call only the relevant MIME type initializers when needed.
+
+        (WebCore::initializePostScriptMIMETypes): Deleted.
+        (WebCore::initializeMIMETypeRegistry): Deleted.
+        (WebCore::MIMETypeRegistry::getPDFAndPostScriptMIMETypes): Deleted.
+
+        Remove an unused and unexported function.
+
+        * platform/MIMETypeRegistry.h:
+
 2017-10-23  Andy Estes  <[email protected]>
 
         [Payment Request] Take the JSC API lock before creating the PaymentResponse.details object

Modified: trunk/Source/WebCore/platform/MIMETypeRegistry.cpp (223859 => 223860)


--- trunk/Source/WebCore/platform/MIMETypeRegistry.cpp	2017-10-23 22:30:23 UTC (rev 223859)
+++ trunk/Source/WebCore/platform/MIMETypeRegistry.cpp	2017-10-23 22:37:33 UTC (rev 223860)
@@ -36,6 +36,7 @@
 #if USE(CG)
 #include "ImageSourceCG.h"
 #include "UTIRegistry.h"
+#include "UTIUtilities.h"
 #include <wtf/RetainPtr.h>
 #endif
 
@@ -60,29 +61,36 @@
 static HashSet<String, ASCIICaseInsensitiveHash>* supportedNonImageMIMETypes;
 static HashSet<String, ASCIICaseInsensitiveHash>* supportedMediaMIMETypes;
 static HashSet<String, ASCIICaseInsensitiveHash>* pdfMIMETypes;
-static HashSet<String, ASCIICaseInsensitiveHash>* pdfAndPostScriptMIMETypes;
 static HashSet<String, ASCIICaseInsensitiveHash>* unsupportedTextMIMETypes;
 
 static void initializeSupportedImageMIMETypes()
 {
 #if USE(CG)
-    HashSet<String>& imageUTIs = allowedImageUTIs();
-    for (auto& imageUTI : imageUTIs) {
-        String mimeType = MIMETypeForImageSourceType(imageUTI);
+    supportedImageResourceMIMETypes = new HashSet<String, ASCIICaseInsensitiveHash>;
+    supportedImageMIMETypes = new HashSet<String, ASCIICaseInsensitiveHash>;
+
+    // This represents the subset of allowed image UTIs for which CoreServices has a corresponding MIME type. Keep this in sync with allowedImageUTIs().
+    static const char* const allowedImageMIMETypes[] = { "image/tiff", "image/gif", "image/jpeg", "image/vnd.microsoft.icon", "image/jp2", "image/png", "image/bmp" };
+    for (auto& mimeType : allowedImageMIMETypes) {
+        supportedImageMIMETypes->add(ASCIILiteral { mimeType });
+        supportedImageResourceMIMETypes->add(ASCIILiteral { mimeType });
+    }
+
+#ifndef NDEBUG
+    for (auto& uti : allowedImageUTIs()) {
+        auto mimeType = MIMETypeForImageSourceType(uti);
         if (!mimeType.isEmpty()) {
-            supportedImageMIMETypes->add(mimeType);
-            supportedImageResourceMIMETypes->add(mimeType);
+            ASSERT(supportedImageMIMETypes->contains(mimeType));
+            ASSERT(supportedImageResourceMIMETypes->contains(mimeType));
         }
     }
 
-    // On Tiger and Leopard, com.microsoft.bmp doesn't have a MIME type in the registry.
-    supportedImageMIMETypes->add("image/bmp");
-    supportedImageResourceMIMETypes->add("image/bmp");
+    for (auto& mime : *supportedImageMIMETypes)
+        ASSERT_UNUSED(mime, allowedImageUTIs().contains(UTIFromMIMEType(mime)));
+#endif
 
     // Favicons don't have a MIME type in the registry either.
-    supportedImageMIMETypes->add("image/vnd.microsoft.icon");
     supportedImageMIMETypes->add("image/x-icon");
-    supportedImageResourceMIMETypes->add("image/vnd.microsoft.icon");
     supportedImageResourceMIMETypes->add("image/x-icon");
 
     //  We only get one MIME type per UTI, hence our need to add these manually
@@ -89,14 +97,6 @@
     supportedImageMIMETypes->add("image/pjpeg");
     supportedImageResourceMIMETypes->add("image/pjpeg");
 
-    //  We don't want to try to treat all binary data as an image
-    supportedImageMIMETypes->remove("application/octet-stream");
-    supportedImageResourceMIMETypes->remove("application/octet-stream");
-
-    //  Don't treat pdf/postscript as images directly
-    supportedImageMIMETypes->remove("application/pdf");
-    supportedImageMIMETypes->remove("application/postscript");
-
 #if PLATFORM(IOS)
     // Add malformed image mimetype for compatibility with Mail and to handle malformed mimetypes from the net
     // These were removed for <rdar://problem/6564538> Re-enable UTI code in WebCore now that MobileCoreServices exists
@@ -203,6 +203,8 @@
         "text/x-_javascript_",
         "text/x-ecmascript"
     };
+
+    supportedJavaScriptMIMETypes = new HashSet<String, ASCIICaseInsensitiveHash>;
     for (auto* type : types)
         supportedJavaScriptMIMETypes->add(type);
 }
@@ -213,15 +215,12 @@
         "application/pdf",
         "text/pdf"
     };
+
+    pdfMIMETypes = new HashSet<String, ASCIICaseInsensitiveHash>;
     for (auto& type : types)
         pdfMIMETypes->add(type);
 }
 
-static void initializePostScriptMIMETypes()
-{
-    pdfAndPostScriptMIMETypes->add("application/postscript");
-}
-
 static void initializeSupportedNonImageMimeTypes()
 {
     static const char* const types[] = {
@@ -247,6 +246,10 @@
         // This can result in cross-site scripting vulnerabilities.
     };
 
+    if (!supportedJavaScriptMIMETypes)
+        initializeSupportedJavaScriptMIMETypes();
+
+    supportedNonImageMIMETypes = new HashSet<String, ASCIICaseInsensitiveHash> { *supportedJavaScriptMIMETypes };
     for (auto& type : types)
         supportedNonImageMIMETypes->add(type);
 
@@ -415,32 +418,12 @@
         "text/vnd.sun.j2me.app-descriptor",
 #endif
     };
+
+    unsupportedTextMIMETypes = new HashSet<String, ASCIICaseInsensitiveHash>;
     for (auto& type : types)
         unsupportedTextMIMETypes->add(ASCIILiteral { type });
 }
 
-static void initializeMIMETypeRegistry()
-{
-    supportedJavaScriptMIMETypes = new HashSet<String, ASCIICaseInsensitiveHash>;
-    initializeSupportedJavaScriptMIMETypes();
-
-    supportedNonImageMIMETypes = new HashSet<String, ASCIICaseInsensitiveHash>(*supportedJavaScriptMIMETypes);
-    initializeSupportedNonImageMimeTypes();
-
-    supportedImageResourceMIMETypes = new HashSet<String, ASCIICaseInsensitiveHash>;
-    supportedImageMIMETypes = new HashSet<String, ASCIICaseInsensitiveHash>;
-    initializeSupportedImageMIMETypes();
-
-    pdfMIMETypes = new HashSet<String, ASCIICaseInsensitiveHash>;
-    initializePDFMIMETypes();
-
-    pdfAndPostScriptMIMETypes = new HashSet<String, ASCIICaseInsensitiveHash>(*pdfMIMETypes);
-    initializePostScriptMIMETypes();
-
-    unsupportedTextMIMETypes = new HashSet<String, ASCIICaseInsensitiveHash>;
-    initializeUnsupportedTextMIMETypes();
-}
-
 String MIMETypeRegistry::getMIMETypeForPath(const String& path)
 {
     size_t pos = path.reverseFind('.');
@@ -458,7 +441,7 @@
     if (mimeType.isEmpty())
         return false;
     if (!supportedImageMIMETypes)
-        initializeMIMETypeRegistry();
+        initializeSupportedImageMIMETypes();
     return supportedImageMIMETypes->contains(getNormalizedMIMEType(mimeType));
 }
 
@@ -472,7 +455,7 @@
     if (mimeType.isEmpty())
         return false;
     if (!supportedImageResourceMIMETypes)
-        initializeMIMETypeRegistry();
+        initializeSupportedImageMIMETypes();
     return supportedImageResourceMIMETypes->contains(getNormalizedMIMEType(mimeType));
 }
 
@@ -492,7 +475,7 @@
     if (mimeType.isEmpty())
         return false;
     if (!supportedJavaScriptMIMETypes)
-        initializeMIMETypeRegistry();
+        initializeSupportedNonImageMimeTypes();
     return supportedJavaScriptMIMETypes->contains(mimeType);
 }
 
@@ -537,7 +520,7 @@
     if (mimeType.isEmpty())
         return false;
     if (!supportedNonImageMIMETypes)
-        initializeMIMETypeRegistry();
+        initializeSupportedNonImageMimeTypes();
     return supportedNonImageMIMETypes->contains(mimeType);
 }
 
@@ -560,7 +543,7 @@
     if (mimeType.isEmpty())
         return false;
     if (!unsupportedTextMIMETypes)
-        initializeMIMETypeRegistry();
+        initializeUnsupportedTextMIMETypes();
     return unsupportedTextMIMETypes->contains(mimeType);
 }
 
@@ -618,11 +601,7 @@
 
 bool MIMETypeRegistry::isPDFOrPostScriptMIMEType(const String& mimeType)
 {
-    if (mimeType.isEmpty())
-        return false;
-    if (!pdfAndPostScriptMIMETypes)
-        initializeMIMETypeRegistry();
-    return pdfAndPostScriptMIMETypes->contains(mimeType);
+    return isPDFMIMEType(mimeType) || mimeType == "application/postscript";
 }
 
 bool MIMETypeRegistry::isPDFMIMEType(const String& mimeType)
@@ -630,7 +609,7 @@
     if (mimeType.isEmpty())
         return false;
     if (!pdfMIMETypes)
-        initializeMIMETypeRegistry();
+        initializePDFMIMETypes();
     return pdfMIMETypes->contains(mimeType);
 }
 
@@ -651,7 +630,7 @@
 HashSet<String, ASCIICaseInsensitiveHash>& MIMETypeRegistry::getSupportedImageMIMETypes()
 {
     if (!supportedImageMIMETypes)
-        initializeMIMETypeRegistry();
+        initializeSupportedImageMIMETypes();
     return *supportedImageMIMETypes;
 }
 
@@ -658,7 +637,7 @@
 HashSet<String, ASCIICaseInsensitiveHash>& MIMETypeRegistry::getSupportedImageResourceMIMETypes()
 {
     if (!supportedImageResourceMIMETypes)
-        initializeMIMETypeRegistry();
+        initializeSupportedImageMIMETypes();
     return *supportedImageResourceMIMETypes;
 }
 
@@ -672,7 +651,7 @@
 HashSet<String, ASCIICaseInsensitiveHash>& MIMETypeRegistry::getSupportedNonImageMIMETypes()
 {
     if (!supportedNonImageMIMETypes)
-        initializeMIMETypeRegistry();
+        initializeSupportedNonImageMimeTypes();
     return *supportedNonImageMIMETypes;
 }
 
@@ -687,21 +666,14 @@
 HashSet<String, ASCIICaseInsensitiveHash>& MIMETypeRegistry::getPDFMIMETypes()
 {
     if (!pdfMIMETypes)
-        initializeMIMETypeRegistry();
+        initializePDFMIMETypes();
     return *pdfMIMETypes;
 }
 
-HashSet<String, ASCIICaseInsensitiveHash>& MIMETypeRegistry::getPDFAndPostScriptMIMETypes()
-{
-    if (!pdfAndPostScriptMIMETypes)
-        initializeMIMETypeRegistry();
-    return *pdfAndPostScriptMIMETypes;
-}
-
 HashSet<String, ASCIICaseInsensitiveHash>& MIMETypeRegistry::getUnsupportedTextMIMETypes()
 {
     if (!unsupportedTextMIMETypes)
-        initializeMIMETypeRegistry();
+        initializeUnsupportedTextMIMETypes();
     return *unsupportedTextMIMETypes;
 }
 

Modified: trunk/Source/WebCore/platform/MIMETypeRegistry.h (223859 => 223860)


--- trunk/Source/WebCore/platform/MIMETypeRegistry.h	2017-10-23 22:30:23 UTC (rev 223859)
+++ trunk/Source/WebCore/platform/MIMETypeRegistry.h	2017-10-23 22:37:33 UTC (rev 223860)
@@ -111,7 +111,6 @@
     WEBCORE_EXPORT static HashSet<String, ASCIICaseInsensitiveHash>& getSupportedNonImageMIMETypes();
     WEBCORE_EXPORT static HashSet<String, ASCIICaseInsensitiveHash>& getSupportedMediaMIMETypes();
     WEBCORE_EXPORT static HashSet<String, ASCIICaseInsensitiveHash>& getPDFMIMETypes();
-    static HashSet<String, ASCIICaseInsensitiveHash>& getPDFAndPostScriptMIMETypes();
     WEBCORE_EXPORT static HashSet<String, ASCIICaseInsensitiveHash>& getUnsupportedTextMIMETypes();
 
     // FIXME: WebKit coding style says we should not have the word "get" in the name of this function.
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to