Skip to content
Permalink
Browse files
[macOS] Display thumbnail of selected file for <input type=file>
https://bugs.webkit.org/show_bug.cgi?id=245993
rdar://100570349

Reviewed by Aditya Keerthi.

On iOS, we show a thumbnail of the selected file, but on macOS, we just
sure the generic file icon based on the file's extension.

This PR adopts the iOS behavior for macOS, and refactors out the thumbnail
decoration logic into `RenderThemeCocoa`. It also refactors out some of the
icon creation logic into common places for both iOS and macOS.

Adding a new file broke some unified build files so it also fixes those.

* Source/WebCore/platform/graphics/Icon.h:
(WebCore::Icon::image const):
(WebCore::Icon::nsImage const): Deleted.
* Source/WebCore/platform/graphics/mac/IconMac.mm:
(WebCore::Icon::Icon):
(WebCore::Icon::~Icon):
(WebCore::Icon::createIconForImage):
(WebCore::Icon::createIconForFiles):
(WebCore::Icon::createIconForFileExtension):
(WebCore::Icon::createIconForUTI):
(WebCore::Icon::paint):
(WebCore::squareCropRectForSize): Deleted.
(WebCore::squareImage): Deleted.
(WebCore::thumbnailSizedImageForImage): Deleted.
(WebCore::iconForImageFile): Deleted.
(WebCore::iconForVideoFile): Deleted.
(WebCore::iconForFile): Deleted.
* Source/WebCore/rendering/RenderThemeMac.mm:
(WebCore::RenderThemeMac::iconForAttachment):
* Source/WebKit/Shared/Cocoa/WebIconUtilities.h: Copied from Source/WebKit/Shared/ios/WebIconUtilities.h.
* Source/WebKit/Shared/Cocoa/WebIconUtilities.mm: Renamed from Source/WebKit/Shared/ios/WebIconUtilities.mm.
(WebKit::squareCropRectForSize):
(WebKit::squareImage):
(WebKit::thumbnailSizedImageForImage):
(WebKit::fallbackIconForFile):
(WebKit::iconForImageFile):
(WebKit::iconForVideoFile):
(WebKit::iconForFiles):
* Source/WebKit/Shared/RemoteLayerTree/RemoteLayerWithRemoteRenderingBackingStoreCollection.h:
* Source/WebKit/Shared/RemoteLayerTree/RemoteLayerWithRemoteRenderingBackingStoreCollection.mm:
(WebKit::RemoteLayerWithRemoteRenderingBackingStoreCollection::allocateBufferForBackingStore):
* Source/WebKit/SourcesCocoa.txt:
* Source/WebKit/UIProcess/ios/forms/WKFileUploadPanel.mm:
(-[_WKImageFileUploadItem displayImage]):
(-[_WKVideoFileUploadItem displayImage]):
(-[WKFileUploadPanel documentPicker:didPickDocumentsAtURLs:]):
* Source/WebKit/WebKit.xcodeproj/project.pbxproj:
* Source/WebKit/WebProcess/GPU/graphics/ImageBufferBackendHandleSharing.h:
* Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::createIconForFiles): Deleted.
* Source/WebKit/WebProcess/WebCoreSupport/WebChromeClientCocoa.mm: Renamed from Source/WebKit/Shared/ios/WebIconUtilities.h.
(WebKit::WebChromeClient::createIconForFiles):
* Source/WebKit/WebProcess/WebCoreSupport/ios/WebChromeClientIOS.mm:
(WebKit::WebChromeClient::createIconForFiles): Deleted.
* Source/WebKitLegacy/mac/WebCoreSupport/WebOpenPanelResultListener.mm:

Canonical link: https://commits.webkit.org/255355@main
  • Loading branch information
rr-codes committed Oct 10, 2022
1 parent 03cd94f commit 43b96844e7e9fc0ceb95e46f46d0b515864d3fa2
Show file tree
Hide file tree
Showing 23 changed files with 277 additions and 165 deletions.
@@ -408,6 +408,7 @@ platform/graphics/cocoa/GraphicsContextGLIOSurfaceSwapChain.cpp
platform/graphics/cocoa/HEVCUtilitiesCocoa.mm
platform/graphics/cocoa/IOSurface.mm
platform/graphics/cocoa/IOSurfacePoolCocoa.mm
platform/graphics/cocoa/IconCocoa.mm
platform/graphics/cocoa/IntRectCocoa.mm
platform/graphics/cocoa/MediaEngineConfigurationFactoryCocoa.cpp
platform/graphics/cocoa/MediaPlaybackTargetContext.mm
@@ -6266,6 +6266,7 @@
0753860114489E9800B78452 /* CachedTextTrack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachedTextTrack.h; sourceTree = "<group>"; };
0754A5E8215EA3B7002D3A99 /* RealtimeMediaSourceFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RealtimeMediaSourceFactory.h; sourceTree = "<group>"; };
0757B13C214AE79700794B0D /* VideoPreset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoPreset.h; sourceTree = "<group>"; };
075CC6C228EE99E100EAAF61 /* IconCocoa.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = IconCocoa.mm; sourceTree = "<group>"; };
07611DB8243FB75C00D80704 /* MediaUsageInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaUsageInfo.h; sourceTree = "<group>"; };
07638A971884487200E15A1B /* MediaSessionManagerIOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaSessionManagerIOS.h; sourceTree = "<group>"; };
07638A981884487200E15A1B /* MediaSessionManagerIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MediaSessionManagerIOS.mm; sourceTree = "<group>"; };
@@ -30183,6 +30184,7 @@
7B6DC81725712E9200380C70 /* GraphicsContextGLIOSurfaceSwapChain.h */,
CDA595962146DF7800A84185 /* HEVCUtilitiesCocoa.h */,
CDA595972146DF7800A84185 /* HEVCUtilitiesCocoa.mm */,
075CC6C228EE99E100EAAF61 /* IconCocoa.mm */,
B27535500B053814002CE64F /* IntRectCocoa.mm */,
2D0B4AA918DA1CCD00434DE1 /* IOSurface.h */,
2D0B4AAA18DA1CCD00434DE1 /* IOSurface.mm */,
@@ -26,11 +26,10 @@
#include <wtf/RefPtr.h>
#include <wtf/RetainPtr.h>

#if PLATFORM(IOS_FAMILY)
#if PLATFORM(COCOA)
#include "NativeImage.h"
#include "PlatformImage.h"
#include <CoreGraphics/CoreGraphics.h>
#elif PLATFORM(MAC)
OBJC_CLASS NSImage;
#elif PLATFORM(WIN)
typedef struct HICON__* HICON;
#endif
@@ -53,25 +52,20 @@ class Icon : public RefCounted<Icon> {
static Ref<Icon> create(HICON hIcon) { return adoptRef(*new Icon(hIcon)); }
#endif

#if PLATFORM(IOS_FAMILY)
// FIXME: Make this work for non-iOS ports and remove the PLATFORM(IOS_FAMILY)-guard.
#if PLATFORM(COCOA)
WEBCORE_EXPORT static RefPtr<Icon> createIconForImage(PlatformImagePtr&&);
RefPtr<NativeImage> image() const { return m_cgImage; }
#endif

#if PLATFORM(MAC)
static RefPtr<Icon> createIconForUTI(const String&);
static RefPtr<Icon> createIconForFileExtension(const String&);

RetainPtr<NSImage> nsImage() const { return m_nsImage; }
#endif

private:
#if PLATFORM(IOS_FAMILY)
#if PLATFORM(COCOA)
Icon(RefPtr<NativeImage>&&);
RefPtr<NativeImage> m_cgImage;
#elif PLATFORM(MAC)
Icon(NSImage*);
RetainPtr<NSImage> m_nsImage;
#elif PLATFORM(WIN)
Icon(HICON);
HICON m_hIcon;
@@ -0,0 +1,68 @@
/*
* Copyright (C) 2007, 2008, 2012 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.
*/

#import "config.h"
#import "Icon.h"

#if PLATFORM(COCOA)

#import "BitmapImage.h"
#import "GraphicsContext.h"

namespace WebCore {

Icon::Icon(RefPtr<NativeImage>&& image)
: m_cgImage(WTFMove(image))
{
ASSERT(m_cgImage);
}

Icon::~Icon()
{
}

RefPtr<Icon> Icon::createIconForImage(PlatformImagePtr&& image)
{
if (!image)
return nullptr;

return adoptRef(new Icon(NativeImage::create(WTFMove(image))));
}

void Icon::paint(GraphicsContext& context, const FloatRect& destRect)
{
if (context.paintingDisabled())
return;

GraphicsContextStateSaver stateSaver(context);

FloatRect srcRect(FloatPoint::zero(), m_cgImage->size());
context.setImageInterpolationQuality(InterpolationQuality::High);
context.drawNativeImage(*m_cgImage, srcRect.size(), destRect, srcRect);
}

}

#endif // PLATFORM(COCOA)
@@ -28,8 +28,14 @@

#if ENABLE(VIDEO) && USE(AVFOUNDATION)
#include "CVUtilities.h"
#include "ImageTransferSessionVT.h"
#include "Logging.h"
#include "NativeImage.h"
#include "PixelBuffer.h"
#include "ProcessIdentity.h"
#include <pal/avfoundation/MediaTimeAVFoundation.h>
#include <pal/cf/AudioToolboxSoftLink.h>
#include <pal/cf/CoreMediaSoftLink.h>
#include <wtf/Scope.h>

#include "CoreVideoSoftLink.h"
@@ -28,46 +28,13 @@

#if PLATFORM(IOS_FAMILY)

#import "BitmapImage.h"
#import "GraphicsContext.h"

namespace WebCore {

Icon::Icon(RefPtr<NativeImage>&& image)
: m_cgImage(WTFMove(image))
{
ASSERT(m_cgImage);
}

Icon::~Icon()
{
}

RefPtr<Icon> Icon::createIconForFiles(const Vector<String>& /*filenames*/)
{
return nullptr;
}

RefPtr<Icon> Icon::createIconForImage(PlatformImagePtr&& image)
{
if (!image)
return nullptr;

return adoptRef(new Icon(NativeImage::create(WTFMove(image))));
}

void Icon::paint(GraphicsContext& context, const FloatRect& destRect)
{
if (context.paintingDisabled())
return;

GraphicsContextStateSaver stateSaver(context);

FloatRect srcRect(FloatPoint::zero(), m_cgImage->size());
context.setImageInterpolationQuality(InterpolationQuality::High);
context.drawNativeImage(*m_cgImage, srcRect.size(), destRect, srcRect);
}

}

#endif // PLATFORM(IOS_FAMILY)
@@ -27,23 +27,14 @@
#import "IntRect.h"
#import "LocalCurrentGraphicsContext.h"
#import "UTIUtilities.h"
#import <AVFoundation/AVFoundation.h>
#import <wtf/RefPtr.h>
#import <wtf/text/WTFString.h>

namespace WebCore {
#import <pal/cf/CoreMediaSoftLink.h>
#import <pal/cocoa/AVFoundationSoftLink.h>

Icon::Icon(NSImage *image)
: m_nsImage(image)
{
// Need this because WebCore uses AppKit's flipped coordinate system exclusively.
ALLOW_DEPRECATED_DECLARATIONS_BEGIN
[image setFlipped:YES];
ALLOW_DEPRECATED_DECLARATIONS_END
}

Icon::~Icon()
{
}
namespace WebCore {

// FIXME: Move the code to ChromeClient::iconForFiles().
RefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
@@ -63,13 +54,15 @@
if (!image)
return nullptr;

return adoptRef(new Icon(image));
PlatformImagePtr platformImage = [image CGImageForProposedRect:nil context:nil hints:nil];
return adoptRef(new Icon(NativeImage::create(WTFMove(platformImage))));
}
NSImage *image = [NSImage imageNamed:NSImageNameMultipleDocuments];
if (!image)
return nullptr;

return adoptRef(new Icon(image));
PlatformImagePtr platformImage = [image CGImageForProposedRect:nil context:nil hints:nil];
return adoptRef(new Icon(NativeImage::create(WTFMove(platformImage))));
}

RefPtr<Icon> Icon::createIconForFileExtension(const String& fileExtension)
@@ -80,7 +73,8 @@
if (!image)
return nullptr;

return adoptRef(new Icon(image));
PlatformImagePtr platformImage = [image CGImageForProposedRect:nil context:nil hints:nil];
return adoptRef(new Icon(NativeImage::create(WTFMove(platformImage))));
}

RefPtr<Icon> Icon::createIconForUTI(const String& UTI)
@@ -91,17 +85,8 @@
if (!image)
return nullptr;

return adoptRef(new Icon(image));
}

void Icon::paint(GraphicsContext& context, const FloatRect& rect)
{
if (context.paintingDisabled())
return;

LocalCurrentGraphicsContext localCurrentGC(context);

[m_nsImage drawInRect:rect fromRect:NSMakeRect(0, 0, [m_nsImage size].width, [m_nsImage size].height) operation:NSCompositingOperationSourceOver fraction:1.0f];
PlatformImagePtr platformImage = [image CGImageForProposedRect:nil context:nil hints:nil];
return adoptRef(new Icon(NativeImage::create(WTFMove(platformImage))));
}

}
@@ -178,7 +178,7 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, const LayoutPoin
else
iconX = contentLeft + contentWidth() - buttonWidth - afterButtonSpacing - iconWidth;

#if PLATFORM(IOS_FAMILY)
#if PLATFORM(COCOA)
if (RenderButton* buttonRenderer = downcast<RenderButton>(button->renderer())) {
// Draw the file icon and decorations.
IntRect iconRect(iconX, iconY, iconWidth, iconHeight);
@@ -25,6 +25,7 @@

#pragma once

#include "Icon.h"
#include "RenderTheme.h"
#include <wtf/RetainPtr.h>

@@ -36,11 +37,16 @@ class RenderThemeCocoa : public RenderTheme {
public:
WEBCORE_EXPORT static RenderThemeCocoa& singleton();

protected:
virtual Color pictureFrameColor(const RenderObject&);

private:
void purgeCaches() override;

bool shouldHaveCapsLockIndicator(const HTMLInputElement&) const final;

void paintFileUploadIconDecorations(const RenderObject& inputRenderer, const RenderObject& buttonRenderer, const PaintInfo&, const IntRect&, Icon*, FileUploadDecorations) override;

#if ENABLE(APPLE_PAY)
void adjustApplePayButtonStyle(RenderStyle&, const Element*) const override;
bool paintApplePayButton(const RenderObject&, const PaintInfo&, const IntRect&) override;
@@ -27,13 +27,15 @@
#import "RenderThemeCocoa.h"

#import "ApplePayLogoSystemImage.h"
#import "FloatRoundedRect.h"
#import "FontCacheCoreText.h"
#import "GraphicsContextCG.h"
#import "HTMLInputElement.h"
#import "ImageBuffer.h"
#import "RenderText.h"
#import "UserAgentScripts.h"
#import "UserAgentStyleSheets.h"
#import <CoreGraphics/CoreGraphics.h>
#import <algorithm>
#import <pal/spi/cf/CoreTextSPI.h>
#import <wtf/Language.h>
@@ -62,6 +64,11 @@ @implementation WebCoreRenderThemeBundle

namespace WebCore {

constexpr int kThumbnailBorderStrokeWidth = 1;
constexpr int kThumbnailBorderCornerRadius = 1;
constexpr int kVisibleBackgroundImageWidth = 1;
constexpr int kMultipleThumbnailShrinkSize = 2;

RenderThemeCocoa& RenderThemeCocoa::singleton()
{
return static_cast<RenderThemeCocoa&>(RenderTheme::singleton());
@@ -83,6 +90,45 @@ @implementation WebCoreRenderThemeBundle
return element.isPasswordField();
}

Color RenderThemeCocoa::pictureFrameColor(const RenderObject& buttonRenderer)
{
return systemColor(CSSValueAppleSystemControlBackground, buttonRenderer.styleColorOptions());
}

void RenderThemeCocoa::paintFileUploadIconDecorations(const RenderObject&, const RenderObject& buttonRenderer, const PaintInfo& paintInfo, const IntRect& rect, Icon* icon, FileUploadDecorations fileUploadDecorations)
{
GraphicsContextStateSaver stateSaver(paintInfo.context());

IntSize cornerSize(kThumbnailBorderCornerRadius, kThumbnailBorderCornerRadius);

auto pictureFrameColor = this->pictureFrameColor(buttonRenderer);

auto thumbnailPictureFrameRect = rect;
auto thumbnailRect = rect;
thumbnailRect.contract(2 * kThumbnailBorderStrokeWidth, 2 * kThumbnailBorderStrokeWidth);
thumbnailRect.move(kThumbnailBorderStrokeWidth, kThumbnailBorderStrokeWidth);

if (fileUploadDecorations == MultipleFiles) {
// Smaller thumbnails for multiple selection appearance.
thumbnailPictureFrameRect.contract(kMultipleThumbnailShrinkSize, kMultipleThumbnailShrinkSize);
thumbnailRect.contract(kMultipleThumbnailShrinkSize, kMultipleThumbnailShrinkSize);

// Background picture frame and simple background icon with a gradient matching the button.
auto backgroundImageColor = buttonRenderer.style().visitedDependentColor(CSSPropertyBackgroundColor);
paintInfo.context().fillRoundedRect(FloatRoundedRect(thumbnailPictureFrameRect, cornerSize, cornerSize, cornerSize, cornerSize), pictureFrameColor);
paintInfo.context().fillRect(thumbnailRect, backgroundImageColor);

// Move the rects for the Foreground picture frame and icon.
auto inset = kVisibleBackgroundImageWidth + kThumbnailBorderStrokeWidth;
thumbnailPictureFrameRect.move(inset, inset);
thumbnailRect.move(inset, inset);
}

// Foreground picture frame and icon.
paintInfo.context().fillRoundedRect(FloatRoundedRect(thumbnailPictureFrameRect, cornerSize, cornerSize, cornerSize, cornerSize), pictureFrameColor);
icon->paint(paintInfo.context(), thumbnailRect);
}

#if ENABLE(APPLE_PAY)

static const auto applePayButtonMinimumWidth = 140;
@@ -87,8 +87,6 @@ class RenderThemeIOS final : public RenderThemeCocoa {
void paintButtonDecorations(const RenderObject&, const PaintInfo&, const IntRect&) override;
void paintPushButtonDecorations(const RenderObject&, const PaintInfo&, const IntRect&) override;

void paintFileUploadIconDecorations(const RenderObject& inputRenderer, const RenderObject& buttonRenderer, const PaintInfo&, const IntRect&, Icon*, FileUploadDecorations) override;

void adjustTextFieldStyle(RenderStyle&, const Element*) const final;
void paintTextFieldDecorations(const RenderBox&, const PaintInfo&, const FloatRect&) override;
void adjustTextAreaStyle(RenderStyle&, const Element*) const final;
@@ -201,6 +199,8 @@ class RenderThemeIOS final : public RenderThemeCocoa {

Color systemColor(CSSValueID, OptionSet<StyleColorOptions>) const override;

Color pictureFrameColor(const RenderObject&) override;

Color controlTintColor(const RenderStyle&, OptionSet<StyleColorOptions>) const;

void adjustStyleForAlternateFormControlDesignTransition(RenderStyle&, const Element*) const;

0 comments on commit 43b9684

Please sign in to comment.