Ignore:
Timestamp:
Jan 21, 2020, 10:28:17 AM (5 years ago)
Author:
[email protected]
Message:

-webkit-image-set should support all the image functions WebKit supports, not just url()
https://bugs.webkit.org/show_bug.cgi?id=81941

Patch by Noam Rosenthal <Noam Rosenthal> on 2020-01-21
Reviewed by Darin Adler.

Source/WebCore:

Separate StyleCachedImage to 4 classes:

  • StyleCachedImage: for single images only
  • StyleMultiImage: for values that can contain multiple images: like cursor/image-set
  • StyleImageSet
  • StyleCursorImage

The new classes only deal with their own value type. Before, ImageSet and cursor were resolved
as a StyleCachedImage, which is no longer a valid assumption if image-set can contain generated images.
Though cursors still can only contain cached images, it was cleaner to refactor it out as well.

Refactored best-fit image selection from loading. Now StyleCachedImage is in charge of loading
the actual image, and StyleImageSet/StyleCursorImage perform the source selection.

Also, added the necessary logic in the CSS parser to consume generated images inside image-sets, excluding
when the image-set is a cursor value.

Tests: fast/css/image-set-parsing-generated.html

fast/hidpi/image-set-cross-fade.html
fast/hidpi/image-set-gradient-multi.html
fast/hidpi/image-set-gradient-single.html
fast/hidpi/image-set-gradient.html

  • Sources.txt:
  • WebCore.xcodeproj/project.pbxproj:

Added new files

  • css/CSSCursorImageValue.cpp:

(WebCore::CSSCursorImageValue::selectBestFitImage):
(WebCore::CSSCursorImageValue::loadImage): Deleted.

  • css/CSSCursorImageValue.h:

Instead of cursor loading the image, it selects an image CSS value

  • css/CSSImageSetValue.cpp:

(WebCore::CSSImageSetValue::CSSImageSetValue):
(WebCore::CSSImageSetValue::fillImageSet):
(WebCore::CSSImageSetValue::cachedImage const):
(WebCore::CSSImageSetValue::selectBestFitImage):
(WebCore::CSSImageSetValue::updateDeviceScaleFactor):
(WebCore::CSSImageSetValue::imageSetWithStylesResolved):
(WebCore::CSSImageSetValue::traverseSubresources const):
(WebCore::CSSImageSetValue::loadBestFitImage): Deleted.

  • css/CSSImageSetValue.h:

Refactor CSSImageSetValue to include non-cachedImage images

  • css/parser/CSSPropertyParser.cpp:

(WebCore::consumeCursor):

  • css/parser/CSSPropertyParserHelpers.cpp:

(WebCore::CSSPropertyParserHelpers::consumeImageSet):
(WebCore::CSSPropertyParserHelpers::consumeImage):
(WebCore::CSSPropertyParserHelpers::consumeUrlOrStringAsStringView): Deleted.

  • css/parser/CSSPropertyParserHelpers.h:
  • page/animation/CSSPropertyAnimation.cpp:

(WebCore::blendFunc):

When blending two images, get the selected images in case it is an image-set

  • rendering/RenderBoxModelObject.cpp:

(WebCore::RenderBoxModelObject::paintFillLayerExtended):

  • rendering/RenderImageResourceStyleImage.cpp:

(WebCore::RenderImageResourceStyleImage::initialize):

  • rendering/RenderLayerBacking.cpp:

(WebCore::canDirectlyCompositeBackgroundBackgroundImage):

  • rendering/style/ShapeValue.cpp:

(WebCore::ShapeValue::isImageValid const):

Use hasCachedImage() instead of isCachedImage() as a StyleImageSet is no longer an isCachedImage()

  • rendering/style/StyleCachedImage.cpp:

(WebCore::StyleCachedImage::StyleCachedImage):
(WebCore::StyleCachedImage::imageURL):
(WebCore::StyleCachedImage::load):

  • rendering/style/StyleCachedImage.h:
  • rendering/style/StyleCursorImage.h:
  • rendering/style/StyleCursorImage.cpp:
  • rendering/style/StyleMultiImage.h:
  • rendering/style/StyleMultiImage.cpp:
  • rendering/style/StyleImageSet.h:
  • rendering/style/StyleImageSet.cpp:
  • rendering/style/StyleImage.h:

(WebCore::StyleImage::selectedImage):
(WebCore::StyleImage::selectedImage const):
(WebCore::StyleImage::isCursorImage const):
(WebCore::StyleImage::isImageSet const):
(WebCore::StyleImage::hasCachedImage const):
(WebCore::StyleImage::StyleImage):

Separate cursor/image-set related stuff away from StyleCachedImage.

  • style/StyleBuilderCustom.h:

(WebCore::Style::BuilderCustom::applyValueContent):

  • style/StyleBuilderState.cpp:

(WebCore::Style::BuilderState::resolveImageStyles):
(WebCore::Style::BuilderState::createStyleImage):

  • style/StyleBuilderState.h:

Match the CSS values with the correct Style class. Also, ensure image-sets resolve their
images' styles as they may contain gradients and other context-aware values.

LayoutTests:

  • fast/css/cursor-parsing-expected.txt:
  • fast/css/cursor-parsing.html:

Added parsing test to ensure arrow image-sets disable generated images

  • fast/css/image-set-parsing-generated-expected.txt: Added.
  • fast/css/image-set-parsing-generated.html: Added.
  • fast/css/image-set-parsing-invalid-expected.txt:
  • fast/css/image-set-parsing-invalid.html:

Added parsing tests for new generated-inside-image-set use cases
Test that image-set inside image-set is not supported

  • fast/hidpi/image-set-cross-fade-expected.html: Added.
  • fast/hidpi/image-set-cross-fade.html: Added.
  • fast/hidpi/image-set-gradient-expected.html: Added.
  • fast/hidpi/image-set-gradient-multi-expected.html: Added.
  • fast/hidpi/image-set-gradient-multi.html: Added.
  • fast/hidpi/image-set-gradient-single-expected.html: Added.
  • fast/hidpi/image-set-gradient-single.html: Added.
  • fast/hidpi/image-set-gradient.html: Added.

Added ref-tests for several generated-inside-image-set use-cases

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/css/CSSImageSetValue.cpp

    r238698 r254861  
    2929#include "CSSImageValue.h"
    3030#include "CSSPrimitiveValue.h"
    31 #include "CachedImage.h"
    32 #include "CachedResourceLoader.h"
    33 #include "CachedResourceRequest.h"
    34 #include "CachedResourceRequestInitiators.h"
    3531#include "Document.h"
    3632#include "Page.h"
     33#include "StyleBuilderState.h"
    3734#include <wtf/text/StringBuilder.h>
    3835
    3936namespace WebCore {
    4037
    41 CSSImageSetValue::CSSImageSetValue(LoadedFromOpaqueSource loadedFromOpaqueSource)
     38Ref<CSSImageSetValue> CSSImageSetValue::create()
     39{
     40    return adoptRef(*new CSSImageSetValue);
     41}
     42
     43CSSImageSetValue::CSSImageSetValue()
    4244    : CSSValueList(ImageSetClass, CommaSeparator)
    43     , m_loadedFromOpaqueSource(loadedFromOpaqueSource)
    4445{
    4546}
     
    5354    while (i < length) {
    5455        CSSValue* imageValue = item(i);
    55         URL imageURL = downcast<CSSImageValue>(*imageValue).url();
    56 
     56        ASSERT(is<CSSImageValue>(imageValue) || is<CSSImageGeneratorValue>(imageValue));
    5757        ++i;
    5858        ASSERT_WITH_SECURITY_IMPLICATION(i < length);
     
    6161
    6262        ImageWithScale image;
    63         image.imageURL = imageURL;
     63        image.value = imageValue;
    6464        image.scaleFactor = scaleFactor;
    6565        m_imagesInSet.append(image);
     
    7171}
    7272
    73 CSSImageSetValue::ImageWithScale CSSImageSetValue::bestImageForScaleFactor()
     73ImageWithScale CSSImageSetValue::bestImageForScaleFactor()
    7474{
    7575    if (!m_imagesInSet.size())
     
    8686}
    8787
    88 std::pair<CachedImage*, float> CSSImageSetValue::loadBestFitImage(CachedResourceLoader& loader, const ResourceLoaderOptions& options)
     88CachedImage* CSSImageSetValue::cachedImage() const
    8989{
    90     Document* document = loader.document();
    91     ASSERT(document);
     90    if (is<CSSImageValue>(m_selectedImageValue))
     91        return downcast<CSSImageValue>(*m_selectedImageValue).cachedImage();
     92    return nullptr;
     93}
    9294
    93     updateDeviceScaleFactor(*document);
     95ImageWithScale CSSImageSetValue::selectBestFitImage(const Document& document)
     96{
     97    updateDeviceScaleFactor(document);
    9498
    9599    if (!m_accessedBestFitImage) {
    96100        m_accessedBestFitImage = true;
     101        m_bestFitImage = bestImageForScaleFactor();
     102    }
    97103
    98         // FIXME: In the future, we want to take much more than deviceScaleFactor into acount here.
    99         // All forms of scale should be included: Page::pageScaleFactor(), Frame::pageZoomFactor(),
    100         // and any CSS transforms. https://bugs.webkit.org/show_bug.cgi?id=81698
    101         ImageWithScale image = bestImageForScaleFactor();
    102 
    103         ResourceLoaderOptions loadOptions = options;
    104         loadOptions.loadedFromOpaqueSource = m_loadedFromOpaqueSource;
    105         CachedResourceRequest request(ResourceRequest(document->completeURL(image.imageURL)), loadOptions);
    106         request.setInitiator(cachedResourceRequestInitiators().css);
    107         if (options.mode == FetchOptions::Mode::Cors)
    108             request.updateForAccessControl(*document);
    109 
    110         m_cachedImage = loader.requestImage(WTFMove(request)).value_or(nullptr);
    111         m_bestFitImageScaleFactor = image.scaleFactor;
    112     }
    113     return { m_cachedImage.get(), m_bestFitImageScaleFactor };
     104    return m_bestFitImage;
    114105}
    115106
    116107void CSSImageSetValue::updateDeviceScaleFactor(const Document& document)
    117108{
     109
     110    // FIXME: In the future, we want to take much more than deviceScaleFactor into acount here.
     111    // All forms of scale should be included: Page::pageScaleFactor(), Frame::pageZoomFactor(),
     112    // and any CSS transforms. https://bugs.webkit.org/show_bug.cgi?id=81698
    118113    float deviceScaleFactor = document.page() ? document.page()->deviceScaleFactor() : 1;
    119114    if (deviceScaleFactor == m_deviceScaleFactor)
     
    121116    m_deviceScaleFactor = deviceScaleFactor;
    122117    m_accessedBestFitImage = false;
    123     m_cachedImage = nullptr;
     118    m_selectedImageValue = nullptr;
     119}
     120
     121Ref<CSSImageSetValue> CSSImageSetValue::imageSetWithStylesResolved(Style::BuilderState& builderState)
     122{
     123    Ref<CSSImageSetValue> result = CSSImageSetValue::create();
     124    size_t length = this->length();
     125    for (size_t i = 0; i + 1 < length; i += 2) {
     126        result->append(builderState.resolveImageStyles(*itemWithoutBoundsCheck(i)));
     127        result->append(*itemWithoutBoundsCheck(i + 1));
     128    }
     129
     130    return result;
    124131}
    125132
     
    156163bool CSSImageSetValue::traverseSubresources(const WTF::Function<bool (const CachedResource&)>& handler) const
    157164{
    158     if (!m_cachedImage)
    159         return false;
    160     return handler(*m_cachedImage);
     165    return m_selectedImageValue && m_selectedImageValue->traverseSubresources(handler);
    161166}
    162167
Note: See TracChangeset for help on using the changeset viewer.