blob: dabbbbcc4a0d8b089834e3eadac757b6f15ba7a6 [file] [log] [blame]
Ben Murdoch591b9582013-07-10 11:41:44 +01001/*
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/loader/cache/CachedResourceLoader.h"
33#include "core/platform/graphics/filters/custom/CustomFilterOperation.h"
34#include "core/rendering/style/ContentData.h"
35#include "core/rendering/style/CursorList.h"
36#include "core/rendering/style/FillLayer.h"
37#include "core/rendering/style/RenderStyle.h"
38#include "core/rendering/style/StyleCachedImage.h"
39#include "core/rendering/style/StyleCachedImageSet.h"
40#include "core/rendering/style/StyleCachedShader.h"
41#include "core/rendering/style/StyleCustomFilterProgram.h"
42#include "core/rendering/style/StyleCustomFilterProgramCache.h"
43#include "core/rendering/style/StyleGeneratedImage.h"
44#include "core/rendering/style/StylePendingImage.h"
45#include "core/rendering/style/StylePendingShader.h"
46
47namespace WebCore {
48
49StyleResourceLoader::StyleResourceLoader(CachedResourceLoader* cachedResourceLoader)
50 : m_cachedResourceLoader(cachedResourceLoader)
51 , m_customFilterProgramCache(StyleCustomFilterProgramCache::create())
52{
53}
54
55void StyleResourceLoader::loadPendingSVGDocuments(RenderStyle* renderStyle, const ElementStyleResources& elementStyleResources)
56{
57 if (!renderStyle->hasFilter() || elementStyleResources.pendingSVGDocuments().isEmpty())
58 return;
59
60 Vector<RefPtr<FilterOperation> >& filterOperations = renderStyle->mutableFilter().operations();
61 for (unsigned i = 0; i < filterOperations.size(); ++i) {
62 RefPtr<FilterOperation> filterOperation = filterOperations.at(i);
63 if (filterOperation->getOperationType() == FilterOperation::REFERENCE) {
64 ReferenceFilterOperation* referenceFilter = static_cast<ReferenceFilterOperation*>(filterOperation.get());
65
66 CSSSVGDocumentValue* value = elementStyleResources.pendingSVGDocuments().get(referenceFilter);
67 if (!value)
68 continue;
69 CachedDocument* cachedDocument = value->load(m_cachedResourceLoader);
70 if (!cachedDocument)
71 continue;
72
73 // Stash the CachedDocument on the reference filter.
74 referenceFilter->setCachedSVGDocumentReference(adoptPtr(new CachedSVGDocumentReference(cachedDocument)));
75 }
76 }
77}
78
79PassRefPtr<StyleImage> StyleResourceLoader::loadPendingImage(StylePendingImage* pendingImage, float deviceScaleFactor)
80{
81 if (pendingImage->cssImageValue()) {
82 CSSImageValue* imageValue = pendingImage->cssImageValue();
83 return imageValue->cachedImage(m_cachedResourceLoader);
84 }
85
86 if (pendingImage->cssImageGeneratorValue()) {
87 CSSImageGeneratorValue* imageGeneratorValue = pendingImage->cssImageGeneratorValue();
88 imageGeneratorValue->loadSubimages(m_cachedResourceLoader);
89 return StyleGeneratedImage::create(imageGeneratorValue);
90 }
91
92 if (pendingImage->cssCursorImageValue()) {
93 CSSCursorImageValue* cursorImageValue = pendingImage->cssCursorImageValue();
94 return cursorImageValue->cachedImage(m_cachedResourceLoader, deviceScaleFactor);
95 }
96
97 if (pendingImage->cssImageSetValue()) {
98 CSSImageSetValue* imageSetValue = pendingImage->cssImageSetValue();
99 return imageSetValue->cachedImageSet(m_cachedResourceLoader, deviceScaleFactor);
100 }
101
102 return 0;
103}
104
105void StyleResourceLoader::loadPendingShapeImage(RenderStyle* renderStyle, ShapeValue* shapeValue)
106{
107 if (!shapeValue)
108 return;
109
110 StyleImage* image = shapeValue->image();
111 if (!image || !image->isPendingImage())
112 return;
113
114 StylePendingImage* pendingImage = static_cast<StylePendingImage*>(image);
115 CSSImageValue* cssImageValue = pendingImage->cssImageValue();
116
117 ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions();
118 options.requestOriginPolicy = RestrictToSameOrigin;
119
120 shapeValue->setImage(cssImageValue->cachedImage(m_cachedResourceLoader, options));
121}
122
123void StyleResourceLoader::loadPendingImages(RenderStyle* style, const ElementStyleResources& elementStyleResources)
124{
125 if (elementStyleResources.pendingImageProperties().isEmpty())
126 return;
127
128 PendingImagePropertyMap::const_iterator::Keys end = elementStyleResources.pendingImageProperties().end().keys();
129 for (PendingImagePropertyMap::const_iterator::Keys it = elementStyleResources.pendingImageProperties().begin().keys(); it != end; ++it) {
130 CSSPropertyID currentProperty = *it;
131
132 switch (currentProperty) {
133 case CSSPropertyBackgroundImage: {
134 for (FillLayer* backgroundLayer = style->accessBackgroundLayers(); backgroundLayer; backgroundLayer = backgroundLayer->next()) {
135 if (backgroundLayer->image() && backgroundLayer->image()->isPendingImage())
136 backgroundLayer->setImage(loadPendingImage(static_cast<StylePendingImage*>(backgroundLayer->image()), elementStyleResources.deviceScaleFactor()));
137 }
138 break;
139 }
140 case CSSPropertyContent: {
141 for (ContentData* contentData = const_cast<ContentData*>(style->contentData()); contentData; contentData = contentData->next()) {
142 if (contentData->isImage()) {
143 StyleImage* image = static_cast<ImageContentData*>(contentData)->image();
144 if (image->isPendingImage()) {
145 RefPtr<StyleImage> loadedImage = loadPendingImage(static_cast<StylePendingImage*>(image), elementStyleResources.deviceScaleFactor());
146 if (loadedImage)
147 static_cast<ImageContentData*>(contentData)->setImage(loadedImage.release());
148 }
149 }
150 }
151 break;
152 }
153 case CSSPropertyCursor: {
154 if (CursorList* cursorList = style->cursors()) {
155 for (size_t i = 0; i < cursorList->size(); ++i) {
156 CursorData& currentCursor = cursorList->at(i);
157 if (StyleImage* image = currentCursor.image()) {
158 if (image->isPendingImage())
159 currentCursor.setImage(loadPendingImage(static_cast<StylePendingImage*>(image), elementStyleResources.deviceScaleFactor()));
160 }
161 }
162 }
163 break;
164 }
165 case CSSPropertyListStyleImage: {
166 if (style->listStyleImage() && style->listStyleImage()->isPendingImage())
167 style->setListStyleImage(loadPendingImage(static_cast<StylePendingImage*>(style->listStyleImage()), elementStyleResources.deviceScaleFactor()));
168 break;
169 }
170 case CSSPropertyBorderImageSource: {
171 if (style->borderImageSource() && style->borderImageSource()->isPendingImage())
172 style->setBorderImageSource(loadPendingImage(static_cast<StylePendingImage*>(style->borderImageSource()), elementStyleResources.deviceScaleFactor()));
173 break;
174 }
175 case CSSPropertyWebkitBoxReflect: {
176 if (StyleReflection* reflection = style->boxReflect()) {
177 const NinePieceImage& maskImage = reflection->mask();
178 if (maskImage.image() && maskImage.image()->isPendingImage()) {
179 RefPtr<StyleImage> loadedImage = loadPendingImage(static_cast<StylePendingImage*>(maskImage.image()), elementStyleResources.deviceScaleFactor());
180 reflection->setMask(NinePieceImage(loadedImage.release(), maskImage.imageSlices(), maskImage.fill(), maskImage.borderSlices(), maskImage.outset(), maskImage.horizontalRule(), maskImage.verticalRule()));
181 }
182 }
183 break;
184 }
185 case CSSPropertyWebkitMaskBoxImageSource: {
186 if (style->maskBoxImageSource() && style->maskBoxImageSource()->isPendingImage())
187 style->setMaskBoxImageSource(loadPendingImage(static_cast<StylePendingImage*>(style->maskBoxImageSource()), elementStyleResources.deviceScaleFactor()));
188 break;
189 }
190 case CSSPropertyWebkitMaskImage: {
191 for (FillLayer* maskLayer = style->accessMaskLayers(); maskLayer; maskLayer = maskLayer->next()) {
192 if (maskLayer->image() && maskLayer->image()->isPendingImage())
193 maskLayer->setImage(loadPendingImage(static_cast<StylePendingImage*>(maskLayer->image()), elementStyleResources.deviceScaleFactor()));
194 }
195 break;
196 }
197 case CSSPropertyWebkitShapeInside:
198 loadPendingShapeImage(style, style->shapeInside());
199 break;
200 case CSSPropertyWebkitShapeOutside:
201 loadPendingShapeImage(style, style->shapeOutside());
202 break;
203 default:
204 ASSERT_NOT_REACHED();
205 }
206 }
207}
208
209void StyleResourceLoader::loadPendingShaders(RenderStyle* style, const ElementStyleResources& elementStyleResources)
210{
211 if (!style->hasFilter() || !elementStyleResources.hasPendingShaders())
212 return;
213
214 Vector<RefPtr<FilterOperation> >& filterOperations = style->mutableFilter().operations();
215 for (unsigned i = 0; i < filterOperations.size(); ++i) {
216 RefPtr<FilterOperation> filterOperation = filterOperations.at(i);
217 if (filterOperation->getOperationType() == FilterOperation::CUSTOM) {
218 CustomFilterOperation* customFilter = static_cast<CustomFilterOperation*>(filterOperation.get());
219 ASSERT(customFilter->program());
220 StyleCustomFilterProgram* program = static_cast<StyleCustomFilterProgram*>(customFilter->program());
221 // Note that the StylePendingShaders could be already resolved to StyleCachedShaders. That's because the rule was matched before.
222 // However, the StyleCustomFilterProgram that was initially created could have been removed from the cache in the meanwhile,
223 // meaning that we get a new StyleCustomFilterProgram here that is not yet in the cache, but already has loaded StyleShaders.
224 if (!program->hasPendingShaders() && program->inCache())
225 continue;
226 RefPtr<StyleCustomFilterProgram> styleProgram = m_customFilterProgramCache->lookup(program);
227 if (styleProgram.get()) {
228 customFilter->setProgram(styleProgram.release());
229 } else {
230 if (program->vertexShader() && program->vertexShader()->isPendingShader()) {
231 CSSShaderValue* shaderValue = static_cast<StylePendingShader*>(program->vertexShader())->cssShaderValue();
232 program->setVertexShader(shaderValue->cachedShader(m_cachedResourceLoader));
233 }
234 if (program->fragmentShader() && program->fragmentShader()->isPendingShader()) {
235 CSSShaderValue* shaderValue = static_cast<StylePendingShader*>(program->fragmentShader())->cssShaderValue();
236 program->setFragmentShader(shaderValue->cachedShader(m_cachedResourceLoader));
237 }
238 m_customFilterProgramCache->add(program);
239 }
240 }
241 }
242}
243
244void StyleResourceLoader::loadPendingResources(RenderStyle* renderStyle, ElementStyleResources& elementStyleResources)
245{
246 // Start loading images referenced by this style.
247 loadPendingImages(renderStyle, elementStyleResources);
248
249 // Start loading the shaders referenced by this style.
250 loadPendingShaders(renderStyle, elementStyleResources);
251
252 // Start loading the SVG Documents referenced by this style.
253 loadPendingSVGDocuments(renderStyle, elementStyleResources);
254
255 // FIXME: Investigate if this clearing is necessary.
256 elementStyleResources.clear();
257}
258
259}