• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
48 namespace WebCore {
49 
StyleResourceLoader(ResourceFetcher * fetcher)50 StyleResourceLoader::StyleResourceLoader(ResourceFetcher* fetcher)
51     : m_customFilterProgramCache(StyleCustomFilterProgramCache::create())
52     , m_fetcher(fetcher)
53 {
54 }
55 
loadPendingSVGDocuments(RenderStyle * renderStyle,const ElementStyleResources & elementStyleResources)56 void 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 
loadPendingImage(StylePendingImage * pendingImage,float deviceScaleFactor)80 PassRefPtr<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 
loadPendingShapeImage(RenderStyle * renderStyle,ShapeValue * shapeValue)106 void 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 
loadPendingImages(RenderStyle * style,const ElementStyleResources & elementStyleResources)124 void 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 
loadPendingShaders(RenderStyle * style,const ElementStyleResources & elementStyleResources)210 void 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 
loadPendingResources(RenderStyle * renderStyle,ElementStyleResources & elementStyleResources)245 void 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