blob: ca5de3394f840908fc90c318007c84261ea53520 [file] [log] [blame]
/*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
* Copyright (C) 2013 Google Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "config.h"
#include "core/css/resolver/StyleResourceLoader.h"
#include "CSSPropertyNames.h"
#include "core/css/CSSCursorImageValue.h"
#include "core/css/CSSImageValue.h"
#include "core/css/CSSSVGDocumentValue.h"
#include "core/css/CSSShaderValue.h"
#include "core/css/resolver/ElementStyleResources.h"
#include "core/fetch/ResourceFetcher.h"
#include "core/platform/graphics/filters/custom/CustomFilterOperation.h"
#include "core/rendering/style/ContentData.h"
#include "core/rendering/style/CursorList.h"
#include "core/rendering/style/FillLayer.h"
#include "core/rendering/style/RenderStyle.h"
#include "core/rendering/style/StyleCustomFilterProgram.h"
#include "core/rendering/style/StyleCustomFilterProgramCache.h"
#include "core/rendering/style/StyleFetchedImage.h"
#include "core/rendering/style/StyleFetchedImageSet.h"
#include "core/rendering/style/StyleFetchedShader.h"
#include "core/rendering/style/StyleGeneratedImage.h"
#include "core/rendering/style/StylePendingImage.h"
#include "core/rendering/style/StylePendingShader.h"
namespace WebCore {
StyleResourceLoader::StyleResourceLoader(ResourceFetcher* fetcher)
: m_fetcher(fetcher)
, m_customFilterProgramCache(StyleCustomFilterProgramCache::create())
{
}
void StyleResourceLoader::loadPendingSVGDocuments(RenderStyle* renderStyle, const ElementStyleResources& elementStyleResources)
{
if (!renderStyle->hasFilter() || elementStyleResources.pendingSVGDocuments().isEmpty())
return;
Vector<RefPtr<FilterOperation> >& filterOperations = renderStyle->mutableFilter().operations();
for (unsigned i = 0; i < filterOperations.size(); ++i) {
RefPtr<FilterOperation> filterOperation = filterOperations.at(i);
if (filterOperation->getOperationType() == FilterOperation::REFERENCE) {
ReferenceFilterOperation* referenceFilter = static_cast<ReferenceFilterOperation*>(filterOperation.get());
CSSSVGDocumentValue* value = elementStyleResources.pendingSVGDocuments().get(referenceFilter);
if (!value)
continue;
DocumentResource* resource = value->load(m_fetcher);
if (!resource)
continue;
// Stash the DocumentResource on the reference filter.
referenceFilter->setDocumentResourceReference(adoptPtr(new DocumentResourceReference(resource)));
}
}
}
PassRefPtr<StyleImage> StyleResourceLoader::loadPendingImage(StylePendingImage* pendingImage, float deviceScaleFactor)
{
if (pendingImage->cssImageValue()) {
CSSImageValue* imageValue = pendingImage->cssImageValue();
return imageValue->cachedImage(m_fetcher);
}
if (pendingImage->cssImageGeneratorValue()) {
CSSImageGeneratorValue* imageGeneratorValue = pendingImage->cssImageGeneratorValue();
imageGeneratorValue->loadSubimages(m_fetcher);
return StyleGeneratedImage::create(imageGeneratorValue);
}
if (pendingImage->cssCursorImageValue()) {
CSSCursorImageValue* cursorImageValue = pendingImage->cssCursorImageValue();
return cursorImageValue->cachedImage(m_fetcher, deviceScaleFactor);
}
if (pendingImage->cssImageSetValue()) {
CSSImageSetValue* imageSetValue = pendingImage->cssImageSetValue();
return imageSetValue->cachedImageSet(m_fetcher, deviceScaleFactor);
}
return 0;
}
void StyleResourceLoader::loadPendingShapeImage(RenderStyle* renderStyle, ShapeValue* shapeValue)
{
if (!shapeValue)
return;
StyleImage* image = shapeValue->image();
if (!image || !image->isPendingImage())
return;
StylePendingImage* pendingImage = static_cast<StylePendingImage*>(image);
CSSImageValue* cssImageValue = pendingImage->cssImageValue();
ResourceLoaderOptions options = ResourceFetcher::defaultResourceOptions();
options.requestOriginPolicy = RestrictToSameOrigin;
shapeValue->setImage(cssImageValue->cachedImage(m_fetcher, options));
}
void StyleResourceLoader::loadPendingImages(RenderStyle* style, const ElementStyleResources& elementStyleResources)
{
if (elementStyleResources.pendingImageProperties().isEmpty())
return;
PendingImagePropertyMap::const_iterator::Keys end = elementStyleResources.pendingImageProperties().end().keys();
for (PendingImagePropertyMap::const_iterator::Keys it = elementStyleResources.pendingImageProperties().begin().keys(); it != end; ++it) {
CSSPropertyID currentProperty = *it;
switch (currentProperty) {
case CSSPropertyBackgroundImage: {
for (FillLayer* backgroundLayer = style->accessBackgroundLayers(); backgroundLayer; backgroundLayer = backgroundLayer->next()) {
if (backgroundLayer->image() && backgroundLayer->image()->isPendingImage())
backgroundLayer->setImage(loadPendingImage(static_cast<StylePendingImage*>(backgroundLayer->image()), elementStyleResources.deviceScaleFactor()));
}
break;
}
case CSSPropertyContent: {
for (ContentData* contentData = const_cast<ContentData*>(style->contentData()); contentData; contentData = contentData->next()) {
if (contentData->isImage()) {
StyleImage* image = static_cast<ImageContentData*>(contentData)->image();
if (image->isPendingImage()) {
RefPtr<StyleImage> loadedImage = loadPendingImage(static_cast<StylePendingImage*>(image), elementStyleResources.deviceScaleFactor());
if (loadedImage)
static_cast<ImageContentData*>(contentData)->setImage(loadedImage.release());
}
}
}
break;
}
case CSSPropertyCursor: {
if (CursorList* cursorList = style->cursors()) {
for (size_t i = 0; i < cursorList->size(); ++i) {
CursorData& currentCursor = cursorList->at(i);
if (StyleImage* image = currentCursor.image()) {
if (image->isPendingImage())
currentCursor.setImage(loadPendingImage(static_cast<StylePendingImage*>(image), elementStyleResources.deviceScaleFactor()));
}
}
}
break;
}
case CSSPropertyListStyleImage: {
if (style->listStyleImage() && style->listStyleImage()->isPendingImage())
style->setListStyleImage(loadPendingImage(static_cast<StylePendingImage*>(style->listStyleImage()), elementStyleResources.deviceScaleFactor()));
break;
}
case CSSPropertyBorderImageSource: {
if (style->borderImageSource() && style->borderImageSource()->isPendingImage())
style->setBorderImageSource(loadPendingImage(static_cast<StylePendingImage*>(style->borderImageSource()), elementStyleResources.deviceScaleFactor()));
break;
}
case CSSPropertyWebkitBoxReflect: {
if (StyleReflection* reflection = style->boxReflect()) {
const NinePieceImage& maskImage = reflection->mask();
if (maskImage.image() && maskImage.image()->isPendingImage()) {
RefPtr<StyleImage> loadedImage = loadPendingImage(static_cast<StylePendingImage*>(maskImage.image()), elementStyleResources.deviceScaleFactor());
reflection->setMask(NinePieceImage(loadedImage.release(), maskImage.imageSlices(), maskImage.fill(), maskImage.borderSlices(), maskImage.outset(), maskImage.horizontalRule(), maskImage.verticalRule()));
}
}
break;
}
case CSSPropertyWebkitMaskBoxImageSource: {
if (style->maskBoxImageSource() && style->maskBoxImageSource()->isPendingImage())
style->setMaskBoxImageSource(loadPendingImage(static_cast<StylePendingImage*>(style->maskBoxImageSource()), elementStyleResources.deviceScaleFactor()));
break;
}
case CSSPropertyWebkitMaskImage: {
for (FillLayer* maskLayer = style->accessMaskLayers(); maskLayer; maskLayer = maskLayer->next()) {
if (maskLayer->image() && maskLayer->image()->isPendingImage())
maskLayer->setImage(loadPendingImage(static_cast<StylePendingImage*>(maskLayer->image()), elementStyleResources.deviceScaleFactor()));
}
break;
}
case CSSPropertyWebkitShapeInside:
loadPendingShapeImage(style, style->shapeInside());
break;
case CSSPropertyWebkitShapeOutside:
loadPendingShapeImage(style, style->shapeOutside());
break;
default:
ASSERT_NOT_REACHED();
}
}
}
void StyleResourceLoader::loadPendingShaders(RenderStyle* style, const ElementStyleResources& elementStyleResources)
{
if (!style->hasFilter() || !elementStyleResources.hasPendingShaders())
return;
Vector<RefPtr<FilterOperation> >& filterOperations = style->mutableFilter().operations();
for (unsigned i = 0; i < filterOperations.size(); ++i) {
RefPtr<FilterOperation> filterOperation = filterOperations.at(i);
if (filterOperation->getOperationType() == FilterOperation::CUSTOM) {
CustomFilterOperation* customFilter = static_cast<CustomFilterOperation*>(filterOperation.get());
ASSERT(customFilter->program());
StyleCustomFilterProgram* program = static_cast<StyleCustomFilterProgram*>(customFilter->program());
// Note that the StylePendingShaders could be already resolved to StyleFetchedShaders. That's because the rule was matched before.
// However, the StyleCustomFilterProgram that was initially created could have been removed from the cache in the meanwhile,
// meaning that we get a new StyleCustomFilterProgram here that is not yet in the cache, but already has loaded StyleShaders.
if (!program->hasPendingShaders() && program->inCache())
continue;
RefPtr<StyleCustomFilterProgram> styleProgram = m_customFilterProgramCache->lookup(program);
if (styleProgram.get()) {
customFilter->setProgram(styleProgram.release());
} else {
if (program->vertexShader() && program->vertexShader()->isPendingShader()) {
CSSShaderValue* shaderValue = static_cast<StylePendingShader*>(program->vertexShader())->cssShaderValue();
program->setVertexShader(shaderValue->resource(m_fetcher));
}
if (program->fragmentShader() && program->fragmentShader()->isPendingShader()) {
CSSShaderValue* shaderValue = static_cast<StylePendingShader*>(program->fragmentShader())->cssShaderValue();
program->setFragmentShader(shaderValue->resource(m_fetcher));
}
m_customFilterProgramCache->add(program);
}
}
}
}
void StyleResourceLoader::loadPendingResources(RenderStyle* renderStyle, ElementStyleResources& elementStyleResources)
{
// Start loading images referenced by this style.
loadPendingImages(renderStyle, elementStyleResources);
// Start loading the shaders referenced by this style.
loadPendingShaders(renderStyle, elementStyleResources);
// Start loading the SVG Documents referenced by this style.
loadPendingSVGDocuments(renderStyle, elementStyleResources);
}
}