1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
4 * Copyright (C) 2013 Google Inc. All rights reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB.  If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23#include "config.h"
24#include "core/css/resolver/StyleResourceLoader.h"
25
26#include "CSSPropertyNames.h"
27#include "core/css/CSSCursorImageValue.h"
28#include "core/css/CSSImageValue.h"
29#include "core/css/CSSSVGDocumentValue.h"
30#include "core/css/CSSShaderValue.h"
31#include "core/css/resolver/ElementStyleResources.h"
32#include "core/fetch/ResourceFetcher.h"
33#include "core/rendering/style/ContentData.h"
34#include "core/rendering/style/CursorList.h"
35#include "core/rendering/style/FillLayer.h"
36#include "core/rendering/style/RenderStyle.h"
37#include "core/rendering/style/StyleCustomFilterProgram.h"
38#include "core/rendering/style/StyleCustomFilterProgramCache.h"
39#include "core/rendering/style/StyleFetchedImage.h"
40#include "core/rendering/style/StyleFetchedImageSet.h"
41#include "core/rendering/style/StyleFetchedShader.h"
42#include "core/rendering/style/StyleGeneratedImage.h"
43#include "core/rendering/style/StylePendingImage.h"
44#include "core/rendering/style/StylePendingShader.h"
45#include "core/rendering/svg/ReferenceFilterBuilder.h"
46#include "platform/graphics/filters/custom/CustomFilterOperation.h"
47
48namespace WebCore {
49
50StyleResourceLoader::StyleResourceLoader(ResourceFetcher* fetcher)
51    : m_customFilterProgramCache(StyleCustomFilterProgramCache::create())
52    , m_fetcher(fetcher)
53{
54}
55
56void StyleResourceLoader::loadPendingSVGDocuments(RenderStyle* renderStyle, const ElementStyleResources& elementStyleResources)
57{
58    if (!renderStyle->hasFilter() || elementStyleResources.pendingSVGDocuments().isEmpty())
59        return;
60
61    Vector<RefPtr<FilterOperation> >& filterOperations = renderStyle->mutableFilter().operations();
62    for (unsigned i = 0; i < filterOperations.size(); ++i) {
63        RefPtr<FilterOperation> filterOperation = filterOperations.at(i);
64        if (filterOperation->type() == FilterOperation::REFERENCE) {
65            ReferenceFilterOperation* referenceFilter = toReferenceFilterOperation(filterOperation.get());
66
67            CSSSVGDocumentValue* value = elementStyleResources.pendingSVGDocuments().get(referenceFilter);
68            if (!value)
69                continue;
70            DocumentResource* resource = value->load(m_fetcher);
71            if (!resource)
72                continue;
73
74            // Stash the DocumentResource on the reference filter.
75            ReferenceFilterBuilder::setDocumentResourceReference(referenceFilter, adoptPtr(new DocumentResourceReference(resource)));
76        }
77    }
78}
79
80PassRefPtr<StyleImage> StyleResourceLoader::loadPendingImage(StylePendingImage* pendingImage, float deviceScaleFactor)
81{
82    if (pendingImage->cssImageValue()) {
83        CSSImageValue* imageValue = pendingImage->cssImageValue();
84        return imageValue->cachedImage(m_fetcher);
85    }
86
87    if (pendingImage->cssImageGeneratorValue()) {
88        CSSImageGeneratorValue* imageGeneratorValue = pendingImage->cssImageGeneratorValue();
89        imageGeneratorValue->loadSubimages(m_fetcher);
90        return StyleGeneratedImage::create(imageGeneratorValue);
91    }
92
93    if (pendingImage->cssCursorImageValue()) {
94        CSSCursorImageValue* cursorImageValue = pendingImage->cssCursorImageValue();
95        return cursorImageValue->cachedImage(m_fetcher, deviceScaleFactor);
96    }
97
98    if (pendingImage->cssImageSetValue()) {
99        CSSImageSetValue* imageSetValue = pendingImage->cssImageSetValue();
100        return imageSetValue->cachedImageSet(m_fetcher, deviceScaleFactor);
101    }
102
103    return 0;
104}
105
106void StyleResourceLoader::loadPendingShapeImage(RenderStyle* renderStyle, ShapeValue* shapeValue)
107{
108    if (!shapeValue)
109        return;
110
111    StyleImage* image = shapeValue->image();
112    if (!image || !image->isPendingImage())
113        return;
114
115    StylePendingImage* pendingImage = toStylePendingImage(image);
116    CSSImageValue* cssImageValue =  pendingImage->cssImageValue();
117
118    ResourceLoaderOptions options = ResourceFetcher::defaultResourceOptions();
119    options.allowCredentials = DoNotAllowStoredCredentials;
120
121    shapeValue->setImage(cssImageValue->cachedImage(m_fetcher, options, PotentiallyCORSEnabled));
122}
123
124void StyleResourceLoader::loadPendingImages(RenderStyle* style, const ElementStyleResources& elementStyleResources)
125{
126    if (elementStyleResources.pendingImageProperties().isEmpty())
127        return;
128
129    PendingImagePropertyMap::const_iterator::Keys end = elementStyleResources.pendingImageProperties().end().keys();
130    for (PendingImagePropertyMap::const_iterator::Keys it = elementStyleResources.pendingImageProperties().begin().keys(); it != end; ++it) {
131        CSSPropertyID currentProperty = *it;
132
133        switch (currentProperty) {
134        case CSSPropertyBackgroundImage: {
135            for (FillLayer* backgroundLayer = style->accessBackgroundLayers(); backgroundLayer; backgroundLayer = backgroundLayer->next()) {
136                if (backgroundLayer->image() && backgroundLayer->image()->isPendingImage())
137                    backgroundLayer->setImage(loadPendingImage(toStylePendingImage(backgroundLayer->image()), elementStyleResources.deviceScaleFactor()));
138            }
139            break;
140        }
141        case CSSPropertyContent: {
142            for (ContentData* contentData = const_cast<ContentData*>(style->contentData()); contentData; contentData = contentData->next()) {
143                if (contentData->isImage()) {
144                    StyleImage* image = static_cast<ImageContentData*>(contentData)->image();
145                    if (image->isPendingImage()) {
146                        RefPtr<StyleImage> loadedImage = loadPendingImage(toStylePendingImage(image), elementStyleResources.deviceScaleFactor());
147                        if (loadedImage)
148                            static_cast<ImageContentData*>(contentData)->setImage(loadedImage.release());
149                    }
150                }
151            }
152            break;
153        }
154        case CSSPropertyCursor: {
155            if (CursorList* cursorList = style->cursors()) {
156                for (size_t i = 0; i < cursorList->size(); ++i) {
157                    CursorData& currentCursor = cursorList->at(i);
158                    if (StyleImage* image = currentCursor.image()) {
159                        if (image->isPendingImage())
160                            currentCursor.setImage(loadPendingImage(toStylePendingImage(image), elementStyleResources.deviceScaleFactor()));
161                    }
162                }
163            }
164            break;
165        }
166        case CSSPropertyListStyleImage: {
167            if (style->listStyleImage() && style->listStyleImage()->isPendingImage())
168                style->setListStyleImage(loadPendingImage(toStylePendingImage(style->listStyleImage()), elementStyleResources.deviceScaleFactor()));
169            break;
170        }
171        case CSSPropertyBorderImageSource: {
172            if (style->borderImageSource() && style->borderImageSource()->isPendingImage())
173                style->setBorderImageSource(loadPendingImage(toStylePendingImage(style->borderImageSource()), elementStyleResources.deviceScaleFactor()));
174            break;
175        }
176        case CSSPropertyWebkitBoxReflect: {
177            if (StyleReflection* reflection = style->boxReflect()) {
178                const NinePieceImage& maskImage = reflection->mask();
179                if (maskImage.image() && maskImage.image()->isPendingImage()) {
180                    RefPtr<StyleImage> loadedImage = loadPendingImage(toStylePendingImage(maskImage.image()), elementStyleResources.deviceScaleFactor());
181                    reflection->setMask(NinePieceImage(loadedImage.release(), maskImage.imageSlices(), maskImage.fill(), maskImage.borderSlices(), maskImage.outset(), maskImage.horizontalRule(), maskImage.verticalRule()));
182                }
183            }
184            break;
185        }
186        case CSSPropertyWebkitMaskBoxImageSource: {
187            if (style->maskBoxImageSource() && style->maskBoxImageSource()->isPendingImage())
188                style->setMaskBoxImageSource(loadPendingImage(toStylePendingImage(style->maskBoxImageSource()), elementStyleResources.deviceScaleFactor()));
189            break;
190        }
191        case CSSPropertyWebkitMaskImage: {
192            for (FillLayer* maskLayer = style->accessMaskLayers(); maskLayer; maskLayer = maskLayer->next()) {
193                if (maskLayer->image() && maskLayer->image()->isPendingImage())
194                    maskLayer->setImage(loadPendingImage(toStylePendingImage(maskLayer->image()), elementStyleResources.deviceScaleFactor()));
195            }
196            break;
197        }
198        case CSSPropertyShapeInside:
199            loadPendingShapeImage(style, style->shapeInside());
200            break;
201        case CSSPropertyShapeOutside:
202            loadPendingShapeImage(style, style->shapeOutside());
203            break;
204        default:
205            ASSERT_NOT_REACHED();
206        }
207    }
208}
209
210void StyleResourceLoader::loadPendingShaders(RenderStyle* style, const ElementStyleResources& elementStyleResources)
211{
212    if (!style->hasFilter() || !elementStyleResources.hasNewCustomFilterProgram())
213        return;
214
215    Vector<RefPtr<FilterOperation> >& filterOperations = style->mutableFilter().operations();
216    for (unsigned i = 0; i < filterOperations.size(); ++i) {
217        RefPtr<FilterOperation> filterOperation = filterOperations.at(i);
218        if (filterOperation->type() == FilterOperation::CUSTOM) {
219            CustomFilterOperation* customFilter = toCustomFilterOperation(filterOperation.get());
220            ASSERT(customFilter->program());
221            StyleCustomFilterProgram* program = static_cast<StyleCustomFilterProgram*>(customFilter->program());
222            // Note that the StylePendingShaders could be already resolved to StyleFetchedShaders. That's because the rule was matched before.
223            // However, the StyleCustomFilterProgram that was initially created could have been removed from the cache in the meanwhile,
224            // meaning that we get a new StyleCustomFilterProgram here that is not yet in the cache, but already has loaded StyleShaders.
225            if (!program->hasPendingShaders() && program->inCache())
226                continue;
227            RefPtr<StyleCustomFilterProgram> styleProgram = m_customFilterProgramCache->lookup(program);
228            if (styleProgram.get()) {
229                customFilter->setProgram(styleProgram.release());
230            } else {
231                if (program->vertexShader() && program->vertexShader()->isPendingShader()) {
232                    CSSShaderValue* shaderValue = static_cast<StylePendingShader*>(program->vertexShader())->cssShaderValue();
233                    program->setVertexShader(shaderValue->resource(m_fetcher));
234                }
235                if (program->fragmentShader() && program->fragmentShader()->isPendingShader()) {
236                    CSSShaderValue* shaderValue = static_cast<StylePendingShader*>(program->fragmentShader())->cssShaderValue();
237                    program->setFragmentShader(shaderValue->resource(m_fetcher));
238                }
239                m_customFilterProgramCache->add(program);
240            }
241        }
242    }
243}
244
245void StyleResourceLoader::loadPendingResources(RenderStyle* renderStyle, ElementStyleResources& elementStyleResources)
246{
247    // Start loading images referenced by this style.
248    loadPendingImages(renderStyle, elementStyleResources);
249
250    // Start loading the shaders referenced by this style.
251    loadPendingShaders(renderStyle, elementStyleResources);
252
253    // Start loading the SVG Documents referenced by this style.
254    loadPendingSVGDocuments(renderStyle, elementStyleResources);
255}
256
257}
258