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 "core/CSSPropertyNames.h" 27#include "core/css/CSSCursorImageValue.h" 28#include "core/css/CSSImageValue.h" 29#include "core/css/CSSSVGDocumentValue.h" 30#include "core/css/resolver/ElementStyleResources.h" 31#include "core/fetch/ResourceFetcher.h" 32#include "core/rendering/style/ContentData.h" 33#include "core/rendering/style/FillLayer.h" 34#include "core/rendering/style/RenderStyle.h" 35#include "core/rendering/style/StyleFetchedImage.h" 36#include "core/rendering/style/StyleFetchedImageSet.h" 37#include "core/rendering/style/StyleGeneratedImage.h" 38#include "core/rendering/style/StylePendingImage.h" 39#include "core/rendering/svg/ReferenceFilterBuilder.h" 40 41namespace blink { 42 43StyleResourceLoader::StyleResourceLoader(ResourceFetcher* fetcher) 44 : m_fetcher(fetcher) 45{ 46} 47 48void StyleResourceLoader::loadPendingSVGDocuments(RenderStyle* renderStyle, ElementStyleResources& elementStyleResources) 49{ 50 if (!renderStyle->hasFilter() || elementStyleResources.pendingSVGDocuments().isEmpty()) 51 return; 52 53 Vector<RefPtr<FilterOperation> >& filterOperations = renderStyle->mutableFilter().operations(); 54 for (unsigned i = 0; i < filterOperations.size(); ++i) { 55 RefPtr<FilterOperation> filterOperation = filterOperations.at(i); 56 if (filterOperation->type() == FilterOperation::REFERENCE) { 57 ReferenceFilterOperation* referenceFilter = toReferenceFilterOperation(filterOperation.get()); 58 59 CSSSVGDocumentValue* value = elementStyleResources.pendingSVGDocuments().get(referenceFilter); 60 if (!value) 61 continue; 62 DocumentResource* resource = value->load(m_fetcher); 63 if (!resource) 64 continue; 65 66 // Stash the DocumentResource on the reference filter. 67 ReferenceFilterBuilder::setDocumentResourceReference(referenceFilter, adoptPtr(new DocumentResourceReference(resource))); 68 } 69 } 70 71 elementStyleResources.clearPendingSVGDocuments(); 72} 73 74static PassRefPtr<StyleImage> doLoadPendingImage(ResourceFetcher* fetcher, StylePendingImage* pendingImage, float deviceScaleFactor, const ResourceLoaderOptions& options) 75{ 76 if (CSSImageValue* imageValue = pendingImage->cssImageValue()) 77 return imageValue->cachedImage(fetcher, options); 78 79 if (CSSImageGeneratorValue* imageGeneratorValue 80 = pendingImage->cssImageGeneratorValue()) { 81 imageGeneratorValue->loadSubimages(fetcher); 82 return StyleGeneratedImage::create(imageGeneratorValue); 83 } 84 85 if (CSSCursorImageValue* cursorImageValue 86 = pendingImage->cssCursorImageValue()) 87 return cursorImageValue->cachedImage(fetcher, deviceScaleFactor); 88 89 if (CSSImageSetValue* imageSetValue = pendingImage->cssImageSetValue()) 90 return imageSetValue->cachedImageSet(fetcher, deviceScaleFactor, options); 91 92 return nullptr; 93} 94 95PassRefPtr<StyleImage> StyleResourceLoader::loadPendingImage(StylePendingImage* pendingImage, float deviceScaleFactor) 96{ 97 return doLoadPendingImage(m_fetcher, pendingImage, deviceScaleFactor, ResourceFetcher::defaultResourceOptions()); 98} 99 100void StyleResourceLoader::loadPendingShapeImage(RenderStyle* renderStyle, ShapeValue* shapeValue, float deviceScaleFactor) 101{ 102 if (!shapeValue) 103 return; 104 105 StyleImage* image = shapeValue->image(); 106 if (!image || !image->isPendingImage()) 107 return; 108 109 ResourceLoaderOptions options = ResourceFetcher::defaultResourceOptions(); 110 options.allowCredentials = DoNotAllowStoredCredentials; 111 options.credentialsRequested = ClientDidNotRequestCredentials; 112 options.corsEnabled = IsCORSEnabled; 113 114 shapeValue->setImage(doLoadPendingImage(m_fetcher, toStylePendingImage(image), deviceScaleFactor, options)); 115} 116 117void StyleResourceLoader::loadPendingImages(RenderStyle* style, ElementStyleResources& elementStyleResources) 118{ 119 if (elementStyleResources.pendingImageProperties().isEmpty()) 120 return; 121 122 PendingImagePropertyMap::const_iterator::Keys end = elementStyleResources.pendingImageProperties().end().keys(); 123 for (PendingImagePropertyMap::const_iterator::Keys it = elementStyleResources.pendingImageProperties().begin().keys(); it != end; ++it) { 124 CSSPropertyID currentProperty = *it; 125 126 switch (currentProperty) { 127 case CSSPropertyBackgroundImage: { 128 for (FillLayer* backgroundLayer = &style->accessBackgroundLayers(); backgroundLayer; backgroundLayer = backgroundLayer->next()) { 129 if (backgroundLayer->image() && backgroundLayer->image()->isPendingImage()) 130 backgroundLayer->setImage(loadPendingImage(toStylePendingImage(backgroundLayer->image()), elementStyleResources.deviceScaleFactor())); 131 } 132 break; 133 } 134 case CSSPropertyContent: { 135 for (ContentData* contentData = const_cast<ContentData*>(style->contentData()); contentData; contentData = contentData->next()) { 136 if (contentData->isImage()) { 137 StyleImage* image = toImageContentData(contentData)->image(); 138 if (image->isPendingImage()) { 139 RefPtr<StyleImage> loadedImage = loadPendingImage(toStylePendingImage(image), elementStyleResources.deviceScaleFactor()); 140 if (loadedImage) 141 toImageContentData(contentData)->setImage(loadedImage.release()); 142 } 143 } 144 } 145 break; 146 } 147 case CSSPropertyCursor: { 148 if (CursorList* cursorList = style->cursors()) { 149 for (size_t i = 0; i < cursorList->size(); ++i) { 150 CursorData& currentCursor = cursorList->at(i); 151 if (StyleImage* image = currentCursor.image()) { 152 if (image->isPendingImage()) 153 currentCursor.setImage(loadPendingImage(toStylePendingImage(image), elementStyleResources.deviceScaleFactor())); 154 } 155 } 156 } 157 break; 158 } 159 case CSSPropertyListStyleImage: { 160 if (style->listStyleImage() && style->listStyleImage()->isPendingImage()) 161 style->setListStyleImage(loadPendingImage(toStylePendingImage(style->listStyleImage()), elementStyleResources.deviceScaleFactor())); 162 break; 163 } 164 case CSSPropertyBorderImageSource: { 165 if (style->borderImageSource() && style->borderImageSource()->isPendingImage()) 166 style->setBorderImageSource(loadPendingImage(toStylePendingImage(style->borderImageSource()), elementStyleResources.deviceScaleFactor())); 167 break; 168 } 169 case CSSPropertyWebkitBoxReflect: { 170 if (StyleReflection* reflection = style->boxReflect()) { 171 const NinePieceImage& maskImage = reflection->mask(); 172 if (maskImage.image() && maskImage.image()->isPendingImage()) { 173 RefPtr<StyleImage> loadedImage = loadPendingImage(toStylePendingImage(maskImage.image()), elementStyleResources.deviceScaleFactor()); 174 reflection->setMask(NinePieceImage(loadedImage.release(), maskImage.imageSlices(), maskImage.fill(), maskImage.borderSlices(), maskImage.outset(), maskImage.horizontalRule(), maskImage.verticalRule())); 175 } 176 } 177 break; 178 } 179 case CSSPropertyWebkitMaskBoxImageSource: { 180 if (style->maskBoxImageSource() && style->maskBoxImageSource()->isPendingImage()) 181 style->setMaskBoxImageSource(loadPendingImage(toStylePendingImage(style->maskBoxImageSource()), elementStyleResources.deviceScaleFactor())); 182 break; 183 } 184 case CSSPropertyWebkitMaskImage: { 185 for (FillLayer* maskLayer = &style->accessMaskLayers(); maskLayer; maskLayer = maskLayer->next()) { 186 if (maskLayer->image() && maskLayer->image()->isPendingImage()) 187 maskLayer->setImage(loadPendingImage(toStylePendingImage(maskLayer->image()), elementStyleResources.deviceScaleFactor())); 188 } 189 break; 190 } 191 case CSSPropertyShapeOutside: 192 loadPendingShapeImage(style, style->shapeOutside(), elementStyleResources.deviceScaleFactor()); 193 break; 194 default: 195 ASSERT_NOT_REACHED(); 196 } 197 } 198 199 elementStyleResources.clearPendingImageProperties(); 200} 201 202void StyleResourceLoader::loadPendingResources(RenderStyle* renderStyle, ElementStyleResources& elementStyleResources) 203{ 204 // Start loading images referenced by this style. 205 loadPendingImages(renderStyle, elementStyleResources); 206 207 // Start loading the SVG Documents referenced by this style. 208 loadPendingSVGDocuments(renderStyle, elementStyleResources); 209} 210 211} 212