blob: de1297df88304dda61867a080da6dd61cf8f0623 [file] [log] [blame]
/*
* Copyright (C) 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.
*/
#include "core/css/CSSImageSetValue.h"
#include "core/css/CSSImageValue.h"
#include "core/css/CSSPrimitiveValue.h"
#include "core/dom/Document.h"
#include "core/fetch/FetchInitiatorTypeNames.h"
#include "core/fetch/FetchRequest.h"
#include "core/fetch/ImageResource.h"
#include "core/fetch/ResourceFetcher.h"
#include "core/fetch/ResourceLoaderOptions.h"
#include "core/frame/Settings.h"
#include "core/style/StyleFetchedImageSet.h"
#include "core/style/StyleInvalidImage.h"
#include "platform/weborigin/KURL.h"
#include "platform/weborigin/SecurityPolicy.h"
#include "wtf/text/StringBuilder.h"
#include <algorithm>
namespace blink {
CSSImageSetValue::CSSImageSetValue()
: CSSValueList(ImageSetClass, CommaSeparator), m_cachedScaleFactor(1) {}
CSSImageSetValue::~CSSImageSetValue() {}
void CSSImageSetValue::fillImageSet() {
size_t length = this->length();
size_t i = 0;
while (i < length) {
const CSSImageValue& imageValue = toCSSImageValue(item(i));
String imageURL = imageValue.url();
++i;
SECURITY_DCHECK(i < length);
const CSSValue& scaleFactorValue = item(i);
float scaleFactor = toCSSPrimitiveValue(scaleFactorValue).getFloatValue();
ImageWithScale image;
image.imageURL = imageURL;
image.referrer = SecurityPolicy::generateReferrer(
imageValue.referrer().referrerPolicy, KURL(ParsedURLString, imageURL),
imageValue.referrer().referrer);
image.scaleFactor = scaleFactor;
m_imagesInSet.append(image);
++i;
}
// Sort the images so that they are stored in order from lowest resolution to
// highest.
std::sort(m_imagesInSet.begin(), m_imagesInSet.end(),
CSSImageSetValue::compareByScaleFactor);
}
CSSImageSetValue::ImageWithScale CSSImageSetValue::bestImageForScaleFactor(
float scaleFactor) {
ImageWithScale image;
size_t numberOfImages = m_imagesInSet.size();
for (size_t i = 0; i < numberOfImages; ++i) {
image = m_imagesInSet.at(i);
if (image.scaleFactor >= scaleFactor)
return image;
}
return image;
}
bool CSSImageSetValue::isCachePending(float deviceScaleFactor) const {
return !m_cachedImage || deviceScaleFactor != m_cachedScaleFactor;
}
StyleImage* CSSImageSetValue::cachedImage(float deviceScaleFactor) const {
ASSERT(!isCachePending(deviceScaleFactor));
return m_cachedImage.get();
}
StyleImage* CSSImageSetValue::cacheImage(
const Document& document,
float deviceScaleFactor,
CrossOriginAttributeValue crossOrigin) {
if (!m_imagesInSet.size())
fillImageSet();
if (isCachePending(deviceScaleFactor)) {
// FIXME: In the future, we want to take much more than deviceScaleFactor
// into acount here. All forms of scale should be included:
// Page::pageScaleFactor(), LocalFrame::pageZoomFactor(), and any CSS
// transforms. https://bugs.webkit.org/show_bug.cgi?id=81698
ImageWithScale image = bestImageForScaleFactor(deviceScaleFactor);
FetchRequest request(ResourceRequest(document.completeURL(image.imageURL)),
FetchInitiatorTypeNames::css);
request.mutableResourceRequest().setHTTPReferrer(image.referrer);
if (crossOrigin != CrossOriginAttributeNotSet)
request.setCrossOriginAccessControl(document.getSecurityOrigin(),
crossOrigin);
if (document.settings() && document.settings()->fetchImagePlaceholders())
request.setAllowImagePlaceholder();
if (ImageResource* cachedImage =
ImageResource::fetch(request, document.fetcher()))
m_cachedImage = StyleFetchedImageSet::create(
cachedImage, image.scaleFactor, this, request.url());
else
m_cachedImage = StyleInvalidImage::create(image.imageURL);
m_cachedScaleFactor = deviceScaleFactor;
}
return m_cachedImage.get();
}
String CSSImageSetValue::customCSSText() const {
StringBuilder result;
result.append("-webkit-image-set(");
size_t length = this->length();
size_t i = 0;
while (i < length) {
if (i > 0)
result.append(", ");
const CSSValue& imageValue = item(i);
result.append(imageValue.cssText());
result.append(' ');
++i;
SECURITY_DCHECK(i < length);
const CSSValue& scaleFactorValue = item(i);
result.append(scaleFactorValue.cssText());
// FIXME: Eventually the scale factor should contain it's own unit
// http://wkb.ug/100120.
// For now 'x' is hard-coded in the parser, so we hard-code it here too.
result.append('x');
++i;
}
result.append(')');
return result.toString();
}
bool CSSImageSetValue::hasFailedOrCanceledSubresources() const {
if (!m_cachedImage)
return false;
if (Resource* cachedResource = m_cachedImage->cachedImage())
return cachedResource->loadFailedOrCanceled();
return true;
}
DEFINE_TRACE_AFTER_DISPATCH(CSSImageSetValue) {
visitor->trace(m_cachedImage);
CSSValueList::traceAfterDispatch(visitor);
}
CSSImageSetValue* CSSImageSetValue::valueWithURLsMadeAbsolute() {
CSSImageSetValue* value = CSSImageSetValue::create();
for (auto& item : *this)
item->isImageValue()
? value->append(*toCSSImageValue(*item).valueWithURLMadeAbsolute())
: value->append(*item);
return value;
}
} // namespace blink