Update CachedResourceLoader::requestResource() to return a WTF::Expected
[WebKit-https.git] / Source / WebCore / css / CSSImageSetValue.cpp
1 /*
2  * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "CSSImageSetValue.h"
28
29 #include "CSSImageValue.h"
30 #include "CSSPrimitiveValue.h"
31 #include "CachedImage.h"
32 #include "CachedResourceLoader.h"
33 #include "CachedResourceRequest.h"
34 #include "CachedResourceRequestInitiators.h"
35 #include "Document.h"
36 #include "Page.h"
37 #include <wtf/text/StringBuilder.h>
38
39 namespace WebCore {
40
41 CSSImageSetValue::CSSImageSetValue()
42     : CSSValueList(ImageSetClass, CommaSeparator)
43 {
44 }
45
46 CSSImageSetValue::~CSSImageSetValue()
47 {
48 }
49
50 void CSSImageSetValue::fillImageSet()
51 {
52     size_t length = this->length();
53     size_t i = 0;
54     while (i < length) {
55         CSSValue* imageValue = item(i);
56         String imageURL = downcast<CSSImageValue>(*imageValue).url();
57
58         ++i;
59         ASSERT_WITH_SECURITY_IMPLICATION(i < length);
60         CSSValue* scaleFactorValue = item(i);
61         float scaleFactor = downcast<CSSPrimitiveValue>(*scaleFactorValue).floatValue();
62
63         ImageWithScale image;
64         image.imageURL = imageURL;
65         image.scaleFactor = scaleFactor;
66         m_imagesInSet.append(image);
67         ++i;
68     }
69
70     // Sort the images so that they are stored in order from lowest resolution to highest.
71     std::sort(m_imagesInSet.begin(), m_imagesInSet.end(), CSSImageSetValue::compareByScaleFactor);
72 }
73
74 CSSImageSetValue::ImageWithScale CSSImageSetValue::bestImageForScaleFactor()
75 {
76     if (!m_imagesInSet.size())
77         fillImageSet();
78
79     ImageWithScale image;
80     size_t numberOfImages = m_imagesInSet.size();
81     for (size_t i = 0; i < numberOfImages; ++i) {
82         image = m_imagesInSet.at(i);
83         if (image.scaleFactor >= m_deviceScaleFactor)
84             return image;
85     }
86     return image;
87 }
88
89 std::pair<CachedImage*, float> CSSImageSetValue::loadBestFitImage(CachedResourceLoader& loader, const ResourceLoaderOptions& options)
90 {
91     Document* document = loader.document();
92     ASSERT(document);
93
94     updateDeviceScaleFactor(*document);
95
96     if (!m_accessedBestFitImage) {
97         m_accessedBestFitImage = true;
98
99         // FIXME: In the future, we want to take much more than deviceScaleFactor into acount here.
100         // All forms of scale should be included: Page::pageScaleFactor(), Frame::pageZoomFactor(),
101         // and any CSS transforms. https://bugs.webkit.org/show_bug.cgi?id=81698
102         ImageWithScale image = bestImageForScaleFactor();
103         CachedResourceRequest request(ResourceRequest(document->completeURL(image.imageURL)), options);
104         request.setInitiator(cachedResourceRequestInitiators().css);
105         if (options.mode == FetchOptions::Mode::Cors)
106             request.updateForAccessControl(*document);
107
108         m_cachedImage = loader.requestImage(WTFMove(request)).valueOr(nullptr);
109         m_bestFitImageScaleFactor = image.scaleFactor;
110     }
111     return { m_cachedImage.get(), m_bestFitImageScaleFactor };
112 }
113
114 void CSSImageSetValue::updateDeviceScaleFactor(const Document& document)
115 {
116     float deviceScaleFactor = document.page() ? document.page()->deviceScaleFactor() : 1;
117     if (deviceScaleFactor == m_deviceScaleFactor)
118         return;
119     m_deviceScaleFactor = deviceScaleFactor;
120     m_accessedBestFitImage = false;
121     m_cachedImage = nullptr;
122 }
123
124 String CSSImageSetValue::customCSSText() const
125 {
126     StringBuilder result;
127     result.appendLiteral("image-set(");
128
129     size_t length = this->length();
130     size_t i = 0;
131     while (i < length) {
132         if (i > 0)
133             result.appendLiteral(", ");
134
135         const CSSValue* imageValue = item(i);
136         result.append(imageValue->cssText());
137         result.append(' ');
138
139         ++i;
140         ASSERT_WITH_SECURITY_IMPLICATION(i < length);
141         const CSSValue* scaleFactorValue = item(i);
142         result.append(scaleFactorValue->cssText());
143         // FIXME: Eventually the scale factor should contain it's own unit http://wkb.ug/100120.
144         // For now 'x' is hard-coded in the parser, so we hard-code it here too.
145         result.append('x');
146
147         ++i;
148     }
149
150     result.append(')');
151     return result.toString();
152 }
153
154 bool CSSImageSetValue::traverseSubresources(const WTF::Function<bool (const CachedResource&)>& handler) const
155 {
156     if (!m_cachedImage)
157         return false;
158     return handler(*m_cachedImage);
159 }
160
161 } // namespace WebCore