CSSImageSetValue.cpp [plain text]
#include "config.h"
#include "CSSImageSetValue.h"
#include "CSSImageValue.h"
#include "CSSPrimitiveValue.h"
#include "CachedImage.h"
#include "CachedResourceLoader.h"
#include "CachedResourceRequest.h"
#include "CachedResourceRequestInitiators.h"
#include "Document.h"
#include "Page.h"
#include <wtf/text/StringBuilder.h>
namespace WebCore {
CSSImageSetValue::CSSImageSetValue()
: CSSValueList(ImageSetClass, CommaSeparator)
{
}
CSSImageSetValue::~CSSImageSetValue()
{
}
void CSSImageSetValue::fillImageSet()
{
size_t length = this->length();
size_t i = 0;
while (i < length) {
CSSValue* imageValue = item(i);
String imageURL = downcast<CSSImageValue>(*imageValue).url();
++i;
ASSERT_WITH_SECURITY_IMPLICATION(i < length);
CSSValue* scaleFactorValue = item(i);
float scaleFactor = downcast<CSSPrimitiveValue>(*scaleFactorValue).floatValue();
ImageWithScale image;
image.imageURL = imageURL;
image.scaleFactor = scaleFactor;
m_imagesInSet.append(image);
++i;
}
std::sort(m_imagesInSet.begin(), m_imagesInSet.end(), CSSImageSetValue::compareByScaleFactor);
}
CSSImageSetValue::ImageWithScale CSSImageSetValue::bestImageForScaleFactor()
{
if (!m_imagesInSet.size())
fillImageSet();
ImageWithScale image;
size_t numberOfImages = m_imagesInSet.size();
for (size_t i = 0; i < numberOfImages; ++i) {
image = m_imagesInSet.at(i);
if (image.scaleFactor >= m_deviceScaleFactor)
return image;
}
return image;
}
std::pair<CachedImage*, float> CSSImageSetValue::loadBestFitImage(CachedResourceLoader& loader, const ResourceLoaderOptions& options)
{
Document* document = loader.document();
ASSERT(document);
updateDeviceScaleFactor(*document);
if (!m_accessedBestFitImage) {
m_accessedBestFitImage = true;
ImageWithScale image = bestImageForScaleFactor();
CachedResourceRequest request(ResourceRequest(document->completeURL(image.imageURL)), options);
request.setInitiator(cachedResourceRequestInitiators().css);
if (options.mode == FetchOptions::Mode::Cors)
request.updateForAccessControl(*document);
m_cachedImage = loader.requestImage(WTFMove(request));
m_bestFitImageScaleFactor = image.scaleFactor;
}
return { m_cachedImage.get(), m_bestFitImageScaleFactor };
}
void CSSImageSetValue::updateDeviceScaleFactor(const Document& document)
{
float deviceScaleFactor = document.page() ? document.page()->deviceScaleFactor() : 1;
if (deviceScaleFactor == m_deviceScaleFactor)
return;
m_deviceScaleFactor = deviceScaleFactor;
m_accessedBestFitImage = false;
m_cachedImage = nullptr;
}
String CSSImageSetValue::customCSSText() const
{
StringBuilder result;
result.appendLiteral("image-set(");
size_t length = this->length();
size_t i = 0;
while (i < length) {
if (i > 0)
result.appendLiteral(", ");
const CSSValue* imageValue = item(i);
result.append(imageValue->cssText());
result.append(' ');
++i;
ASSERT_WITH_SECURITY_IMPLICATION(i < length);
const CSSValue* scaleFactorValue = item(i);
result.append(scaleFactorValue->cssText());
result.append('x');
++i;
}
result.append(')');
return result.toString();
}
bool CSSImageSetValue::traverseSubresources(const WTF::Function<bool (const CachedResource&)>& handler) const
{
if (!m_cachedImage)
return false;
return handler(*m_cachedImage);
}
}