Home | History | Annotate | Download | only in resolver
      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