1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) 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/ResourceFetcher.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/StyleCustomFilterProgram.h" 39 #include "core/rendering/style/StyleCustomFilterProgramCache.h" 40 #include "core/rendering/style/StyleFetchedImage.h" 41 #include "core/rendering/style/StyleFetchedImageSet.h" 42 #include "core/rendering/style/StyleFetchedShader.h" 43 #include "core/rendering/style/StyleGeneratedImage.h" 44 #include "core/rendering/style/StylePendingImage.h" 45 #include "core/rendering/style/StylePendingShader.h" 46 47 namespace WebCore { 48 49 StyleResourceLoader::StyleResourceLoader(ResourceFetcher* fetcher) 50 : m_fetcher(fetcher) 51 , m_customFilterProgramCache(StyleCustomFilterProgramCache::create()) 52 { 53 } 54 55 void 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 DocumentResource* resource = value->load(m_fetcher); 70 if (!resource) 71 continue; 72 73 // Stash the DocumentResource on the reference filter. 74 referenceFilter->setDocumentResourceReference(adoptPtr(new DocumentResourceReference(resource))); 75 } 76 } 77 } 78 79 PassRefPtr<StyleImage> StyleResourceLoader::loadPendingImage(StylePendingImage* pendingImage, float deviceScaleFactor) 80 { 81 if (pendingImage->cssImageValue()) { 82 CSSImageValue* imageValue = pendingImage->cssImageValue(); 83 return imageValue->cachedImage(m_fetcher); 84 } 85 86 if (pendingImage->cssImageGeneratorValue()) { 87 CSSImageGeneratorValue* imageGeneratorValue = pendingImage->cssImageGeneratorValue(); 88 imageGeneratorValue->loadSubimages(m_fetcher); 89 return StyleGeneratedImage::create(imageGeneratorValue); 90 } 91 92 if (pendingImage->cssCursorImageValue()) { 93 CSSCursorImageValue* cursorImageValue = pendingImage->cssCursorImageValue(); 94 return cursorImageValue->cachedImage(m_fetcher, deviceScaleFactor); 95 } 96 97 if (pendingImage->cssImageSetValue()) { 98 CSSImageSetValue* imageSetValue = pendingImage->cssImageSetValue(); 99 return imageSetValue->cachedImageSet(m_fetcher, deviceScaleFactor); 100 } 101 102 return 0; 103 } 104 105 void 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 = ResourceFetcher::defaultResourceOptions(); 118 options.requestOriginPolicy = RestrictToSameOrigin; 119 120 shapeValue->setImage(cssImageValue->cachedImage(m_fetcher, options)); 121 } 122 123 void 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 209 void 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 StyleFetchedShaders. 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->resource(m_fetcher)); 233 } 234 if (program->fragmentShader() && program->fragmentShader()->isPendingShader()) { 235 CSSShaderValue* shaderValue = static_cast<StylePendingShader*>(program->fragmentShader())->cssShaderValue(); 236 program->setFragmentShader(shaderValue->resource(m_fetcher)); 237 } 238 m_customFilterProgramCache->add(program); 239 } 240 } 241 } 242 } 243 244 void 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 } 260