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/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 
     50 StyleResourceLoader::StyleResourceLoader(ResourceFetcher* fetcher)
     51     : m_customFilterProgramCache(StyleCustomFilterProgramCache::create())
     52     , m_fetcher(fetcher)
     53 {
     54 }
     55 
     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 
     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 
    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 
    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 
    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 
    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