Skip to content

Commit

Permalink
Add support for icon_variants in Web Extensions.
Browse files Browse the repository at this point in the history
https://webkit.org/b/278818
rdar://problem/134885372

Reviewed by Brian Weinstein.

Add support for `icon_variants` manifest parsing under the `WK_WEB_EXTENSIONS_ICON_VARIANTS` flag,
with optimizations to ensure efficient icon loading.

This change introduces `icon_variants` manifest parsing, explicitly supporting different icon sets,
such as dark mode icons. To achieve this efficiently, icons are now cached by size, reducing disk
I/O by avoiding repeated loads when the browser frequently requests the same icon. The cache is
automatically invalidated when device scales change, such as when connecting or disconnecting a
display with a different scale factor.

Only the necessary icons are loaded based on the specific scale factor of all screens, halving the
image loads compared to previous behavior. This ensures that even as more extensions adopt dark
mode icons, typical image loads remain at two images (light and dark).

Proposal: https://github.com/w3c/webextensions/blob/main/proposals/dark_mode_extension_icons.md
WECG issue: w3c/webextensions#229

* Source/WTF/wtf/PlatformEnableCocoa.h: Added ENABLE_WK_WEB_EXTENSIONS_ICON_VARIANTS.
* Source/WebCore/en.lproj/Localizable.strings: Updated.
* Source/WebKit/Platform/cocoa/CocoaHelpers.h:
* Source/WebKit/Platform/cocoa/CocoaHelpers.mm:
(WebKit::availableScreenScales): Added.
(WebKit::largestDisplayScale): Added.
* Source/WebKit/Platform/spi/ios/UIKitSPI.h:
* Source/WebKit/UIProcess/Extensions/Cocoa/WebExtensionActionCocoa.mm:
(WebKit::WebExtensionAction::icon):
* Source/WebKit/UIProcess/Extensions/Cocoa/WebExtensionCocoa.mm:
(WebKit::WebExtension::icon):
(WebKit::WebExtension::actionIcon):
(WebKit::WebExtension::populateActionPropertiesIfNeeded):
(WebKit::WebExtension::populateSidebarActionProperties):
(WebKit::WebExtension::populateSidePanelProperties):
(WebKit::WebExtension::imageForPath):
(WebKit::WebExtension::bestSizeInIconsDictionary): Added.
(WebKit::WebExtension::pathForBestImageInIconsDictionary):
(WebKit::WebExtension::bestImageInIconsDictionary):
(WebKit::WebExtension::bestImageForIconsDictionaryManifestKey):
(WebKit::toColorSchemes): Added.
(WebKit::WebExtension::iconsDictionaryForBestIconVariant): Added.
(WebKit::WebExtension::bestImageForIconVariants): Added.
(WebKit::WebExtension::bestImageForIconVariantsManifestKey): Added.
* Source/WebKit/UIProcess/Extensions/Cocoa/WebExtensionMenuItemCocoa.mm:
(WebKit::WebExtensionMenuItem::icon const):
* Source/WebKit/UIProcess/Extensions/WebExtension.h:
* Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebExtension.mm:
(TestWebKitAPI::TEST(WKWebExtension, MultipleIconVariants)): Added.
(TestWebKitAPI::TEST(WKWebExtension, SingleIconVariant)): Added.
(TestWebKitAPI::TEST(WKWebExtension, AnySizeIconVariant)): Added.
(TestWebKitAPI::TEST(WKWebExtension, NoIconVariants)): Added.
(TestWebKitAPI::TEST(WKWebExtension, IconsAndIconVariantsSpecified)): Added.
(TestWebKitAPI::TEST(WKWebExtension, ActionIconVariantsMultiple)): Added.
(TestWebKitAPI::TEST(WKWebExtension, ActionIconSingleVariant)): Added.
(TestWebKitAPI::TEST(WKWebExtension, ActionIconAnySizeVariant)): Added.
(TestWebKitAPI::TEST(WKWebExtension, ActionNoIconVariants)): Added.
(TestWebKitAPI::TEST(WKWebExtension, ActionIconsAndIconVariantsSpecified)): Added.
* Tools/TestWebKitAPI/cocoa/WebExtensionUtilities.h:
* Tools/TestWebKitAPI/cocoa/WebExtensionUtilities.mm:
(TestWebKitAPI::Util::performWithAppearance): Added.
(TestWebKitAPI::Util::pixelColor): Added.
(TestWebKitAPI::Util::toSRGBColor): Added.
(TestWebKitAPI::Util::compareColors): Added.

Canonical link: https://commits.webkit.org/283118@main
  • Loading branch information
xeenon committed Sep 3, 2024
1 parent 960090f commit 56a9103
Show file tree
Hide file tree
Showing 14 changed files with 862 additions and 132 deletions.
9 changes: 8 additions & 1 deletion Source/WTF/wtf/PlatformEnableCocoa.h
Original file line number Diff line number Diff line change
Expand Up @@ -1014,10 +1014,17 @@
#define ENABLE_WIRELESS_PLAYBACK_TARGET_AVAILABILITY_API 1
#endif

#if !defined(ENABLE_WK_WEB_EXTENSIONS) && (PLATFORM(MAC) || PLATFORM(MACCATALYST) || PLATFORM(IOS) || PLATFORM(IOS_SIMULATOR) || PLATFORM(VISION))
#if !defined(ENABLE_WK_WEB_EXTENSIONS) && (PLATFORM(MAC) || PLATFORM(MACCATALYST) || PLATFORM(IOS) || PLATFORM(VISION))
#define ENABLE_WK_WEB_EXTENSIONS 1
#endif

#if !defined(ENABLE_WK_WEB_EXTENSIONS_ICON_VARIANTS) \
&& ((PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 150500) \
|| ((PLATFORM(IOS) || PLATFORM(MACCATALYST)) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 180500) \
|| (PLATFORM(VISION) && __VISION_OS_VERSION_MAX_ALLOWED >= 20500))
#define ENABLE_WK_WEB_EXTENSIONS_ICON_VARIANTS ENABLE_WK_WEB_EXTENSIONS
#endif

#if !defined(ENABLE_WK_WEB_EXTENSIONS_SIDEBAR)
#define ENABLE_WK_WEB_EXTENSIONS_SIDEBAR 0 && ENABLE_WK_WEB_EXTENSIONS
#endif
Expand Down
15 changes: 15 additions & 0 deletions Source/WebCore/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,15 @@
/* WKWebExtensionErrorInvalidManifestEntry description for externally_connectable */
"Empty or invalid `externally_connectable` manifest entry." = "Empty or invalid `externally_connectable` manifest entry.";

/* WKWebExtensionErrorInvalidManifestEntry description for icon_variants in action only */
"Empty or invalid `icon_variants` for the `action` manifest entry." = "Empty or invalid `icon_variants` for the `action` manifest entry.";

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

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

/* WKWebExtensionErrorInvalidManifestEntry description for invalid new tab entry */
"Empty or invalid `newtab` manifest entry." = "Empty or invalid `newtab` manifest entry.";

Expand Down Expand Up @@ -616,6 +625,12 @@
/* 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.";

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

/* WKWebExtensionErrorInvalidIcon description for failing to load image variants */
"Failed to load images in `icon_variants` manifest entry." = "Failed to load images in `icon_variants` 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.";

Expand Down
3 changes: 3 additions & 0 deletions Source/WebKit/Platform/cocoa/CocoaHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ NSString *escapeCharactersInString(NSString *, NSString *charactersToEscape);

void callAfterRandomDelay(Function<void()>&&);

NSSet *availableScreenScales();
CGFloat largestDisplayScale();

NSDate *toAPI(const WallTime&);
WallTime toImpl(NSDate *);

Expand Down
38 changes: 38 additions & 0 deletions Source/WebKit/Platform/cocoa/CocoaHelpers.mm
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@
#import <wtf/BlockPtr.h>
#import <wtf/FileSystem.h>

#if PLATFORM(IOS_FAMILY)
#import <UIKit/UIKit.h>
#endif

namespace WebKit {

static NSString * const privacyPreservingDescriptionKey = @"privacyPreservingDescription";
Expand Down Expand Up @@ -440,6 +444,40 @@ void callAfterRandomDelay(Function<void()>&& completionHandler)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay.nanosecondsAs<int64_t>()), dispatch_get_main_queue(), makeBlockPtr(WTFMove(completionHandler)).get());
}

NSSet *availableScreenScales()
{
NSMutableSet *screenScales = [NSMutableSet set];

#if USE(APPKIT)
for (NSScreen *screen in NSScreen.screens)
[screenScales addObject:@(screen.backingScaleFactor)];
#else
ALLOW_DEPRECATED_DECLARATIONS_BEGIN
for (UIScreen *screen in UIScreen.screens)
[screenScales addObject:@(screen.scale)];
ALLOW_DEPRECATED_DECLARATIONS_END
#endif

if (screenScales.count)
return [screenScales copy];

// Assume 1x if we got no results. This can happen on headless devices (bots).
return [NSSet setWithObject:@1];
}

CGFloat largestDisplayScale()
{
auto largestDisplayScale = 1.0;

for (NSNumber *scale in availableScreenScales()) {
auto doubleValue = scale.doubleValue;
if (doubleValue > largestDisplayScale)
largestDisplayScale = doubleValue;
}

return largestDisplayScale;
}

NSDate *toAPI(const WallTime& time)
{
if (time.isNaN())
Expand Down
10 changes: 10 additions & 0 deletions Source/WebKit/Platform/spi/ios/UIKitSPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#import <UIKit/UIFont_Private.h>
#import <UIKit/UIGeometry_Private.h>
#import <UIKit/UIGestureRecognizer_Private.h>
#import <UIKit/UIImageAsset_Private.h>
#import <UIKit/UIImagePickerController_Private.h>
#import <UIKit/UIImage_Private.h>
#import <UIKit/UIInterface_Private.h>
Expand Down Expand Up @@ -338,13 +339,18 @@ typedef enum {
@property (nonatomic, setter=_setShowsFileSizePicker:) BOOL _showsFileSizePicker;
@end

@interface UIImageAsset ()
+ (instancetype)_dynamicAssetNamed:(NSString *)name generator:(UIImage *(^)(UIImageAsset *, UIImageConfiguration *, UIImage *))block;
@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;
+ (UIImage *)_imageWithCGSVGDocument:(CGSVGDocumentRef)cgSVGDocument scale:(CGFloat)scale orientation:(UIImageOrientation)orientation;
@end

@protocol UIKeyboardImplGeometryDelegate
Expand Down Expand Up @@ -1105,6 +1111,10 @@ typedef NS_ENUM(NSUInteger, _UIScrollDeviceCategory) {
+ (UIColor *)insertionPointColor;
@end

@interface UIImage ()
- (UIImage *)_rasterizedImage;
@end

@interface UIView (IPI)
- (UIScrollView *)_scroller;
- (CGPoint)accessibilityConvertPointFromSceneReferenceCoordinates:(CGPoint)point;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -646,11 +646,12 @@ - (void)_otherPopoverWillShow:(NSNotification *)notification
return nil;

if (m_customIcons) {
NSError *error;
if (CocoaImage *result = extensionContext()->extension().bestImageInIconsDictionary(m_customIcons.get(), idealSize.width > idealSize.height ? idealSize.width : idealSize.height, &error))
return result;
auto *result = extensionContext()->extension().bestImageInIconsDictionary(m_customIcons.get(), idealSize, [&](auto *error) {
extensionContext()->recordError(error);
});

extensionContext()->recordErrorIfNeeded(error);
if (result)
return result;

// If custom icons fail, fallback to the default icons.
}
Expand Down
Loading

0 comments on commit 56a9103

Please sign in to comment.