Extract UTI mapping and allow for additions
[WebKit-https.git] / Source / WebCore / css / CSSImageSetValue.cpp
1 /*
2  * Copyright (C) 2012-2017 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(LoadedFromOpaqueSource loadedFromOpaqueSource)
42     : CSSValueList(ImageSetClass, CommaSeparator)
43     , m_loadedFromOpaqueSource(loadedFromOpaqueSource)
44 {
45 }
46
47 CSSImageSetValue::~CSSImageSetValue() = default;
48
49 void CSSImageSetValue::fillImageSet()
50 {
51     size_t length = this->length();
52     size_t i = 0;
53     while (i < length) {
54         CSSValue* imageValue = item(i);
55         URL imageURL = downcast<CSSImageValue>(*imageValue).url();
56
57         ++i;
58         ASSERT_WITH_SECURITY_IMPLICATION(i < length);
59         CSSValue* scaleFactorValue = item(i);
60         float scaleFactor = downcast<CSSPrimitiveValue>(*scaleFactorValue).floatValue();
61
62         ImageWithScale image;
63         image.imageURL = imageURL;
64         image.scaleFactor = scaleFactor;
65         m_imagesInSet.append(image);
66         ++i;
67     }
68
69     // Sort the images so that they are stored in order from lowest resolution to highest.
70     std::sort(m_imagesInSet.begin(), m_imagesInSet.end(), CSSImageSetValue::compareByScaleFactor);
71 }
72
73 CSSImageSetValue::ImageWithScale CSSImageSetValue::bestImageForScaleFactor()
74 {
75     if (!m_imagesInSet.size())
76         fillImageSet();
77
78     ImageWithScale image;
79     size_t numberOfImages = m_imagesInSet.size();
80     for (size_t i = 0; i < numberOfImages; ++i) {
81         image = m_imagesInSet.at(i);
82         if (image.scaleFactor >= m_deviceScaleFactor)
83             return image;
84     }
85     return image;
86 }
87
88 std::pair<CachedImage*, float> CSSImageSetValue::loadBestFitImage(CachedResourceLoader& loader, const ResourceLoaderOptions& options)
89 {
90     Document* document = loader.document();
91     ASSERT(document);
92
93     updateDeviceScaleFactor(*document);
94
95     if (!m_accessedBestFitImage) {
96         m_accessedBestFitImage = true;
97
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 };
114 }
115
116 void CSSImageSetValue::updateDeviceScaleFactor(const Document& document)
117 {
118     float deviceScaleFactor = document.page() ? document.page()->deviceScaleFactor() : 1;
119     if (deviceScaleFactor == m_deviceScaleFactor)
120         return;
121     m_deviceScaleFactor = deviceScaleFactor;
122     m_accessedBestFitImage = false;
123     m_cachedImage = nullptr;
124 }
125
126 String CSSImageSetValue::customCSSText() const
127 {
128     StringBuilder result;
129     result.appendLiteral("image-set(");
130
131     size_t length = this->length();
132     size_t i = 0;
133     while (i < length) {
134         if (i > 0)
135             result.appendLiteral(", ");
136
137         const CSSValue* imageValue = item(i);
138         result.append(imageValue->cssText());
139         result.append(' ');
140
141         ++i;
142         ASSERT_WITH_SECURITY_IMPLICATION(i < length);
143         const CSSValue* scaleFactorValue = item(i);
144         result.append(scaleFactorValue->cssText());
145         // FIXME: Eventually the scale factor should contain it's own unit http://wkb.ug/100120.
146         // For now 'x' is hard-coded in the parser, so we hard-code it here too.
147         result.append('x');
148
149         ++i;
150     }
151
152     result.append(')');
153     return result.toString();
154 }
155
156 bool CSSImageSetValue::traverseSubresources(const WTF::Function<bool (const CachedResource&)>& handler) const
157 {
158     if (!m_cachedImage)
159         return false;
160     return handler(*m_cachedImage);
161 }
162
163 } // namespace WebCore