Skip to content

Commit

Permalink
Add Web Extension support for loading images and parsing icons, `ac…
Browse files Browse the repository at this point in the history
…tion`, `browser_action`, and `page_action`.

https://bugs.webkit.org/show_bug.cgi?id=246168

Reviewed by Brian Weinstein.

Added support for loading and validating resources from the extension. This is now used for loading the
manifest.json file and also icons. The icons are generated using the platform's image class. On macOS
the 1x and 2x sizes are retrieved and put into a single NSImage. On iOS the largest scale factor is used
based on the main UIScreen scale. SVG images are also supported via some SPIs.

This loading mechanism is now also used for the special "_generated_background_page.html" path. It will also
be used to load content scripts and stylesheets for injected content.

* Source/WTF/wtf/PlatformUse.h: Added USE_NSIMAGE_FOR_SVG_SUPPORT define.
* Source/WTF/wtf/spi/cocoa/SecuritySPI.h: Added SecCodeValidateFileResource.
* Source/WebCore/PAL/pal/spi/mac/NSImageSPI.h: Added _NSSVGImageRep class.
* Source/WebCore/en.lproj/Localizable.strings: Updated with update-webkit-localizable-strings.
* Source/WebCore/platform/LocalizedStrings.h: Exported formatLocalizedString to use in WebKit.
* Source/WebKit/Platform/spi/Cocoa/CoreSVGSPI.h: Added.
* Source/WebKit/Platform/spi/Cocoa/FoundationSPI.h: Added.
* Source/WebKit/Platform/spi/ios/UIKitSPI.h: Added _imageWithCGSVGDocument: method to UIImage.
* Source/WebKit/UIProcess/API/Cocoa/_WKWebExtension.h:
Simplify the exposed enum values for _WKWebExtensionError to reduce API surface and stay nimble.
* Source/WebKit/UIProcess/API/Cocoa/_WKWebExtension.mm:
(-[_WKWebExtension _initWithManifestDictionary:]):
(-[_WKWebExtension _initWithManifestDictionary:resources:]): Added.
(-[_WKWebExtension _initWithResources:]): Renamed from _initWithManifestData:.
(-[_WKWebExtension displayActionLabel]): Added.
(-[_WKWebExtension iconForSize:]): Added.
(-[_WKWebExtension actionIconForSize:]): Added.
* Source/WebKit/UIProcess/API/Cocoa/_WKWebExtensionPrivate.h:
* Source/WebKit/UIProcess/Extensions/Cocoa/WebExtensionCocoa.mm:
(WebKit::WebExtension::WebExtension):
(WebKit::WebExtension::manifest):
(WebKit::WebExtension::bundleStaticCode): Added.
(WebKit::WebExtension::validateResourceData): Added.
(WebKit::WebExtension::resourceFileURLForPath): Added.
(WebKit::WebExtension::resourceDataForPath): Added.
(WebKit::WebExtension::createError): Tweaked strings and API enum values used.
(WebKit::WebExtension::errors): Call populateActionPropertiesIfNeeded.
(WebKit::WebExtension::icon): Added.
(WebKit::WebExtension::actionIcon): Added.
(WebKit::WebExtension::displayActionLabel): Added.
(WebKit::WebExtension::actionPopupPath): Added.
(WebKit::WebExtension::populateActionPropertiesIfNeeded): Added.
(WebKit::WebExtension::imageForPath): Added.
(WebKit::WebExtension::pathForBestImageInIconsDictionary): Added.
(WebKit::WebExtension::bestImageInIconsDictionary): Added.
(WebKit::WebExtension::bestImageForIconsDictionaryManifestKey): Added.
* Source/WebKit/UIProcess/Extensions/WebExtension.h:
* Source/WebKit/WebKit.xcodeproj/project.pbxproj:
* Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebExtension.mm:
 Added ActionParsing test and tweaks error enum names.

Canonical link: https://commits.webkit.org/255284@main
  • Loading branch information
xeenon committed Oct 7, 2022
1 parent 755130c commit 9aac1c9
Show file tree
Hide file tree
Showing 15 changed files with 811 additions and 99 deletions.
4 changes: 4 additions & 0 deletions Source/WTF/wtf/PlatformUse.h
Expand Up @@ -301,6 +301,10 @@
#define USE_CTFONTGETADVANCES_WORKAROUND 1
#endif

#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 130000)
#define USE_NSIMAGE_FOR_SVG_SUPPORT 1
#endif

#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 120000) \
|| ((PLATFORM(IOS) || PLATFORM(MACCATALYST)) && __IPHONE_OS_VERSION_MIN_REQUIRED < 150000) \
|| (PLATFORM(WATCHOS) && __WATCH_OS_VERSION_MIN_REQUIRED < 80000) \
Expand Down
3 changes: 2 additions & 1 deletion Source/WTF/wtf/spi/cocoa/SecuritySPI.h
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015-2021 Apple Inc. All rights reserved.
* Copyright (C) 2015-2022 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
Expand Down Expand Up @@ -29,6 +29,7 @@

#include <Security/SecAccessControlPriv.h>
#include <Security/SecCertificatePriv.h>
#include <Security/SecCodePriv.h>
#include <Security/SecIdentityPriv.h>
#include <Security/SecItemPriv.h>
#include <Security/SecKeyPriv.h>
Expand Down
8 changes: 8 additions & 0 deletions Source/WebCore/PAL/pal/spi/mac/NSImageSPI.h
Expand Up @@ -48,6 +48,14 @@ NS_ASSUME_NONNULL_END

#endif

NS_ASSUME_NONNULL_BEGIN

@interface _NSSVGImageRep : NSImageRep
- (nullable instancetype)initWithData:(NSData *)data;
@end

NS_ASSUME_NONNULL_END

#if HAVE(ALTERNATE_ICONS)

NS_ASSUME_NONNULL_BEGIN
Expand Down
60 changes: 45 additions & 15 deletions Source/WebCore/en.lproj/Localizable.strings
Expand Up @@ -460,20 +460,23 @@
/* Display name for easy reader (i.e. 3rd-grade level) text tracks. */
"Easy Reader (text track)" = "Easy Reader";

/* WKWebExtensionErrorInvalidBackgroundContent description */
/* WKWebExtensionErrorInvalidManifestEntry description for URL overrides */
"Empty or invalid URL overrides manifest entry" = "Empty or invalid URL overrides manifest entry";

/* WKWebExtensionErrorInvalidManifestEntry description for background */
"Empty or invalid `background` manifest entry." = "Empty or invalid `background` manifest entry.";

/* WKWebExtensionErrorInvalidContentScripts description */
/* WKWebExtensionErrorInvalidManifestEntry description for content_scripts */
"Empty or invalid `content_scripts` manifest entry." = "Empty or invalid `content_scripts` manifest entry.";

/* WKWebExtensionErrorInvalidActionIcon description */
"Empty or invalid `default_icon` for the `action`, `browser_action`, or `page_action` manifest entry." = "Empty or invalid `default_icon` for the `action`, `browser_action`, or `page_action` manifest entry.";
/* WKWebExtensionErrorInvalidManifestEntry description for default_icon in action only */
"Empty or invalid `default_icon` for the `action` manifest entry." = "Empty or invalid `default_icon` for the `action` manifest entry.";

/* WKWebExtensionErrorInvalidExternallyConnectable description */
"Empty or invalid `externally_connectable` manifest entry." = "Empty or invalid `externally_connectable` manifest entry.";
/* WKWebExtensionErrorInvalidManifestEntry description for default_icon in browser_action or page_action */
"Empty or invalid `default_icon` for the `browser_action` or `page_action` manifest entry." = "Empty or invalid `default_icon` for the `browser_action` or `page_action` manifest entry.";

/* WKWebExtensionErrorInvalidURLOverrides description */
"Empty or invalid url overrides manifest entry" = "Empty or invalid url overrides manifest entry";
/* WKWebExtensionErrorInvalidManifestEntry description for externally_connectable */
"Empty or invalid `externally_connectable` manifest entry." = "Empty or invalid `externally_connectable` manifest entry.";

/* Video Enter Full Screen context menu item */
"Enter Full Screen" = "Enter Full Screen";
Expand Down Expand Up @@ -508,6 +511,21 @@
/* menu item */
"Exit Picture in Picture" = "Exit Picture in Picture";

/* WKWebExtensionErrorInvalidActionIcon description for failing to load single image for action */
"Failed to load image for `default_icon` in the `action` manifest entry." = "Failed to load image for `default_icon` in the `action` manifest entry.";

/* WKWebExtensionErrorInvalidActionIcon description for failing to load single image for browser_action or page_action */
"Failed to load image for `default_icon` in the `browser_action` or `page_action` manifest entry." = "Failed to load image for `default_icon` in the `browser_action` or `page_action` manifest entry.";

/* WKWebExtensionErrorInvalidActionIcon description for failing to load images for action only */
"Failed to load images in `default_icon` for the `action` manifest entry." = "Failed to load images in `default_icon` for the `action` manifest entry.";

/* WKWebExtensionErrorInvalidActionIcon description for failing to load images for browser_action or page_action */
"Failed to load images in `default_icon` for the `browser_action` or `page_action` manifest entry." = "Failed to load images in `default_icon` for the `browser_action` or `page_action` manifest entry.";

/* WKWebExtensionErrorInvalidIcon description for failing to load images */
"Failed to load images in `icons` manifest entry." = "Failed to load images in `icons` manifest entry.";

/* The requested file doesn't exist */
"File does not exist" = "File does not exist";

Expand Down Expand Up @@ -610,7 +628,7 @@
/* WKWebExtensionErrorInvalidBackgroundPersistence description for iOS */
"Invalid `persistent` manifest entry. A non-persistent background is required on iOS and iPadOS." = "Invalid `persistent` manifest entry. A non-persistent background is required on iOS and iPadOS.";

/* WKWebExtensionErrorInvalidWebAccessibleResources description */
/* WKWebExtensionErrorInvalidManifestEntry description for web_accessible_resources */
"Invalid `web_accessible_resources` manifest entry." = "Invalid `web_accessible_resources` manifest entry.";

/* Validation message for input form controls with a value not matching type */
Expand Down Expand Up @@ -739,16 +757,22 @@
/* Label text to be used when a plugin is missing */
"Missing Plug-in" = "Missing Plug-in";

/* WKWebExtensionErrorInvalidDescription description */
/* WKWebExtensionErrorInvalidManifestEntry description for action only */
"Missing or empty `action` manifest entry." = "Missing or empty `action` manifest entry.";

/* WKWebExtensionErrorInvalidManifestEntry description for browser_action or page_action */
"Missing or empty `browser_action` or `page_action` manifest entry." = "Missing or empty `browser_action` or `page_action` manifest entry.";

/* WKWebExtensionErrorInvalidManifestEntry description for description */
"Missing or empty `description` manifest entry." = "Missing or empty `description` manifest entry.";

/* WKWebExtensionErrorInvalidIcon description */
/* WKWebExtensionErrorInvalidManifestEntry description for icons */
"Missing or empty `icons` manifest entry." = "Missing or empty `icons` manifest entry.";

/* WKWebExtensionErrorInvalidName description */
/* WKWebExtensionErrorInvalidManifestEntry description for name */
"Missing or empty `name` manifest entry." = "Missing or empty `name` manifest entry.";

/* WKWebExtensionErrorInvalidVersion description */
/* WKWebExtensionErrorInvalidManifestEntry description for version */
"Missing or empty `version` manifest entry." = "Missing or empty `version` manifest entry.";

/* Media Mute context menu item */
Expand Down Expand Up @@ -1237,8 +1261,11 @@
/* accessibility role description for a URL field. */
"URL field" = "URL field";

/* WKWebExtensionErrorManifestNotFound description */
"Unable to find `manifest.json` in the extension bundle." = "Unable to find `manifest.json` in the extension bundle.";
/* WKWebExtensionErrorResourceNotFound description with file name */
"Unable to find \"%@\" in the extension’s resources." = "Unable to find \"%@\" in the extension’s resources.";

/* WKWebExtensionErrorResourceNotFound description with invalid file path */
"Unable to find \"%@\" in the extension’s resources. It is an invalid path." = "Unable to find \"%@\" in the extension’s resources. It is an invalid path.";

/* WKWebExtensionErrorInvalidDeclarativeNetRequest description */
"Unable to parse `declarativeNetRequest` rules because of an unexpected error." = "Unable to parse `declarativeNetRequest` rules because of an unexpected error.";
Expand All @@ -1252,6 +1279,9 @@
/* WKWebExtensionErrorInvalidManifest description, because of a JSON error */
"Unable to parse manifest: %@" = "Unable to parse manifest: %@";

/* WKWebExtensionErrorInvalidResourceCodeSignature description with file name */
"Unable to validate \"%@\" with the extension’s code signature. It likely has been modified since the extension was built." = "Unable to validate \"%@\" with the extension’s code signature. It likely has been modified since the extension was built.";

/* Unacceptable TLS certificate error */
"Unacceptable TLS certificate" = "Unacceptable TLS certificate";

Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/platform/LocalizedStrings.h
Expand Up @@ -451,9 +451,9 @@ namespace WebCore {
#endif

#if USE(CF) && !PLATFORM(WIN)
String formatLocalizedString(CFStringRef format, ...) CF_FORMAT_FUNCTION(1, 2);
WEBCORE_EXPORT String formatLocalizedString(CFStringRef format, ...) CF_FORMAT_FUNCTION(1, 2);
#else
String formatLocalizedString(const char* format, ...) WTF_ATTRIBUTE_PRINTF(1, 2);
WEBCORE_EXPORT String formatLocalizedString(const char* format, ...) WTF_ATTRIBUTE_PRINTF(1, 2);
#endif

#ifdef __OBJC__
Expand Down
43 changes: 43 additions & 0 deletions Source/WebKit/Platform/spi/Cocoa/CoreSVGSPI.h
@@ -0,0 +1,43 @@
/*
* Copyright (C) 2022 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/

#pragma once

#if USE(APPLE_INTERNAL_SDK)

#include <CoreSVG/CGSVGDocument.h>

#else

WTF_EXTERN_C_BEGIN

typedef struct CGSVGDocument *CGSVGDocumentRef;

CGSVGDocumentRef CGSVGDocumentCreateFromData(CFDataRef, CFDictionaryRef);
void CGSVGDocumentRelease(CGSVGDocumentRef);

WTF_EXTERN_C_END

#endif // USE(APPLE_INTERNAL_SDK)
38 changes: 38 additions & 0 deletions Source/WebKit/Platform/spi/Cocoa/FoundationSPI.h
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2022 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/

#pragma once

#if USE(APPLE_INTERNAL_SDK)

#include <Foundation/NSPrivateDecls.h>

#else

@interface NSBundle ()
- (CFBundleRef)_cfBundle;
@end

#endif // USE(APPLE_INTERNAL_SDK)
6 changes: 5 additions & 1 deletion Source/WebKit/Platform/spi/ios/UIKitSPI.h
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Apple Inc. All rights reserved.
* Copyright (C) 2014-2022 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
Expand Down Expand Up @@ -27,6 +27,7 @@

#if USE(APPLE_INTERNAL_SDK)

#import <CoreSVG/CGSVGDocument.h>
#import <UIKit/NSTextAlternatives.h>
#import <UIKit/UIAlertController_Private.h>
#import <UIKit/UIApplication_Private.h>
Expand Down Expand Up @@ -398,10 +399,13 @@ typedef enum {
@property (nonatomic, setter=_setShowsFileSizePicker:) BOOL _showsFileSizePicker;
@end

typedef struct CGSVGDocument *CGSVGDocumentRef;

@interface UIImage ()
- (id)initWithCGImage:(CGImageRef)CGImage imageOrientation:(UIImageOrientation)imageOrientation;
- (UIImage *)_flatImageWithColor:(UIColor *)color;
+ (UIImage *)_systemImageNamed:(NSString *)name;
+ (UIImage *)_imageWithCGSVGDocument:(CGSVGDocumentRef)cgSVGDocument;
@end

@interface UIKeyCommand ()
Expand Down
31 changes: 19 additions & 12 deletions Source/WebKit/UIProcess/API/Cocoa/_WKWebExtension.h
Expand Up @@ -30,27 +30,25 @@
#import <WebKit/_WKWebExtensionPermission.h>
#import <WebKit/_WKWebExtensionMatchPattern.h>

#if TARGET_OS_IPHONE
@class UIImage;
#else
@class NSImage;
#endif

NS_ASSUME_NONNULL_BEGIN

WK_EXTERN NSErrorDomain const _WKWebExtensionErrorDomain WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));

typedef NS_ERROR_ENUM(_WKWebExtensionErrorDomain, _WKWebExtensionError) {
_WKWebExtensionErrorUnknown = 1,
_WKWebExtensionErrorManifestNotFound,
_WKWebExtensionErrorResourceNotFound,
_WKWebExtensionErrorInvalidResourceCodeSignature,
_WKWebExtensionErrorInvalidManifest,
_WKWebExtensionErrorUnsupportedManifestVersion,
_WKWebExtensionErrorInvalidActionIcon,
_WKWebExtensionErrorInvalidBackgroundContent,
_WKWebExtensionErrorInvalidManifestEntry,
_WKWebExtensionErrorInvalidDeclarativeNetRequestEntry,
_WKWebExtensionErrorInvalidBackgroundPersistence,
_WKWebExtensionErrorInvalidContentScripts,
_WKWebExtensionErrorInvalidDeclarativeNetRequest,
_WKWebExtensionErrorInvalidDescription,
_WKWebExtensionErrorInvalidExternallyConnectable,
_WKWebExtensionErrorInvalidIcon,
_WKWebExtensionErrorInvalidName,
_WKWebExtensionErrorInvalidURLOverrides,
_WKWebExtensionErrorInvalidVersion,
_WKWebExtensionErrorInvalidWebAccessibleResources,
_WKWebExtensionErrorBackgroundContentFailedToLoad,
} NS_SWIFT_NAME(_WKWebExtension.Error) WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));

Expand All @@ -77,9 +75,18 @@ WK_CLASS_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA))
@property (readonly, nullable, nonatomic) NSString *displayShortName;
@property (readonly, nullable, nonatomic) NSString *displayVersion;
@property (readonly, nullable, nonatomic) NSString *displayDescription;
@property (readonly, nullable, nonatomic) NSString *displayActionLabel;

@property (readonly, nullable, nonatomic) NSString *version;

#if TARGET_OS_IPHONE
- (nullable UIImage *)iconForSize:(CGSize)size;
- (nullable UIImage *)actionIconForSize:(CGSize)size;
#else
- (nullable NSImage *)iconForSize:(CGSize)size;
- (nullable NSImage *)actionIconForSize:(CGSize)size;
#endif

@property (readonly, nonatomic) NSSet<_WKWebExtensionPermission> *requestedPermissions;
@property (readonly, nonatomic) NSSet<_WKWebExtensionPermission> *optionalPermissions;

Expand Down

0 comments on commit 9aac1c9

Please sign in to comment.