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
41 namespace blink {
42
StyleResourceLoader(ResourceFetcher * fetcher)43 StyleResourceLoader::StyleResourceLoader(ResourceFetcher* fetcher)
44 : m_fetcher(fetcher)
45 {
46 }
47
loadPendingSVGDocuments(RenderStyle * renderStyle,ElementStyleResources & elementStyleResources)48 void 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
doLoadPendingImage(ResourceFetcher * fetcher,StylePendingImage * pendingImage,float deviceScaleFactor,const ResourceLoaderOptions & options)74 static 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
loadPendingImage(StylePendingImage * pendingImage,float deviceScaleFactor)95 PassRefPtr<StyleImage> StyleResourceLoader::loadPendingImage(StylePendingImage* pendingImage, float deviceScaleFactor)
96 {
97 return doLoadPendingImage(m_fetcher, pendingImage, deviceScaleFactor, ResourceFetcher::defaultResourceOptions());
98 }
99
loadPendingShapeImage(RenderStyle * renderStyle,ShapeValue * shapeValue,float deviceScaleFactor)100 void 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
loadPendingImages(RenderStyle * style,ElementStyleResources & elementStyleResources)117 void 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
loadPendingResources(RenderStyle * renderStyle,ElementStyleResources & elementStyleResources)202 void 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