Home | History | Annotate | Download | only in css
      1 /*
      2  * Copyright (C) 2012 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
     14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
     17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     23  * THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "core/css/CSSImageSetValue.h"
     28 
     29 #include "FetchInitiatorTypeNames.h"
     30 #include "core/css/CSSImageValue.h"
     31 #include "core/css/CSSPrimitiveValue.h"
     32 #include "core/dom/Document.h"
     33 #include "core/fetch/FetchRequest.h"
     34 #include "core/fetch/ImageResource.h"
     35 #include "core/fetch/ResourceFetcher.h"
     36 #include "core/rendering/style/StyleFetchedImageSet.h"
     37 #include "core/rendering/style/StylePendingImage.h"
     38 #include "wtf/text/StringBuilder.h"
     39 
     40 namespace WebCore {
     41 
     42 CSSImageSetValue::CSSImageSetValue()
     43     : CSSValueList(ImageSetClass, CommaSeparator)
     44     , m_accessedBestFitImage(false)
     45     , m_scaleFactor(1)
     46 {
     47 }
     48 
     49 CSSImageSetValue::~CSSImageSetValue()
     50 {
     51     if (m_imageSet && m_imageSet->isImageResourceSet())
     52         toStyleFetchedImageSet(m_imageSet)->clearImageSetValue();
     53 }
     54 
     55 void CSSImageSetValue::fillImageSet()
     56 {
     57     size_t length = this->length();
     58     size_t i = 0;
     59     while (i < length) {
     60         CSSValue* imageValue = item(i);
     61         String imageURL = toCSSImageValue(imageValue)->url();
     62 
     63         ++i;
     64         ASSERT_WITH_SECURITY_IMPLICATION(i < length);
     65         CSSValue* scaleFactorValue = item(i);
     66         float scaleFactor = toCSSPrimitiveValue(scaleFactorValue)->getFloatValue();
     67 
     68         ImageWithScale image;
     69         image.imageURL = imageURL;
     70         image.scaleFactor = scaleFactor;
     71         m_imagesInSet.append(image);
     72         ++i;
     73     }
     74 
     75     // Sort the images so that they are stored in order from lowest resolution to highest.
     76     std::sort(m_imagesInSet.begin(), m_imagesInSet.end(), CSSImageSetValue::compareByScaleFactor);
     77 }
     78 
     79 CSSImageSetValue::ImageWithScale CSSImageSetValue::bestImageForScaleFactor()
     80 {
     81     ImageWithScale image;
     82     size_t numberOfImages = m_imagesInSet.size();
     83     for (size_t i = 0; i < numberOfImages; ++i) {
     84         image = m_imagesInSet.at(i);
     85         if (image.scaleFactor >= m_scaleFactor)
     86             return image;
     87     }
     88     return image;
     89 }
     90 
     91 StyleFetchedImageSet* CSSImageSetValue::cachedImageSet(ResourceFetcher* loader, float deviceScaleFactor)
     92 {
     93     ASSERT(loader);
     94 
     95     m_scaleFactor = deviceScaleFactor;
     96 
     97     if (!m_imagesInSet.size())
     98         fillImageSet();
     99 
    100     if (!m_accessedBestFitImage) {
    101         // FIXME: In the future, we want to take much more than deviceScaleFactor into acount here.
    102         // All forms of scale should be included: Page::pageScaleFactor(), Frame::pageZoomFactor(),
    103         // and any CSS transforms. https://bugs.webkit.org/show_bug.cgi?id=81698
    104         ImageWithScale image = bestImageForScaleFactor();
    105         if (Document* document = loader->document()) {
    106             FetchRequest request(ResourceRequest(document->completeURL(image.imageURL)), FetchInitiatorTypeNames::css);
    107             if (ResourcePtr<ImageResource> cachedImage = loader->fetchImage(request)) {
    108                 m_imageSet = StyleFetchedImageSet::create(cachedImage.get(), image.scaleFactor, this);
    109                 m_accessedBestFitImage = true;
    110             }
    111         }
    112     }
    113 
    114     return (m_imageSet && m_imageSet->isImageResourceSet()) ? toStyleFetchedImageSet(m_imageSet) : 0;
    115 }
    116 
    117 StyleImage* CSSImageSetValue::cachedOrPendingImageSet(float deviceScaleFactor)
    118 {
    119     if (!m_imageSet) {
    120         m_imageSet = StylePendingImage::create(this);
    121     } else if (!m_imageSet->isPendingImage()) {
    122         // If the deviceScaleFactor has changed, we may not have the best image loaded, so we have to re-assess.
    123         if (deviceScaleFactor != m_scaleFactor) {
    124             m_accessedBestFitImage = false;
    125             m_imageSet = StylePendingImage::create(this);
    126         }
    127     }
    128 
    129     return m_imageSet.get();
    130 }
    131 
    132 String CSSImageSetValue::customCSSText() const
    133 {
    134     StringBuilder result;
    135     result.append("-webkit-image-set(");
    136 
    137     size_t length = this->length();
    138     size_t i = 0;
    139     while (i < length) {
    140         if (i > 0)
    141             result.append(", ");
    142 
    143         const CSSValue* imageValue = item(i);
    144         result.append(imageValue->cssText());
    145         result.append(' ');
    146 
    147         ++i;
    148         ASSERT_WITH_SECURITY_IMPLICATION(i < length);
    149         const CSSValue* scaleFactorValue = item(i);
    150         result.append(scaleFactorValue->cssText());
    151         // FIXME: Eventually the scale factor should contain it's own unit http://wkb.ug/100120.
    152         // For now 'x' is hard-coded in the parser, so we hard-code it here too.
    153         result.append('x');
    154 
    155         ++i;
    156     }
    157 
    158     result.append(")");
    159     return result.toString();
    160 }
    161 
    162 bool CSSImageSetValue::hasFailedOrCanceledSubresources() const
    163 {
    164     if (!m_imageSet || !m_imageSet->isImageResourceSet())
    165         return false;
    166     if (Resource* cachedResource = toStyleFetchedImageSet(m_imageSet)->cachedImage())
    167         return cachedResource->loadFailedOrCanceled();
    168     return true;
    169 }
    170 
    171 CSSImageSetValue::CSSImageSetValue(const CSSImageSetValue& cloneFrom)
    172     : CSSValueList(cloneFrom)
    173     , m_accessedBestFitImage(false)
    174     , m_scaleFactor(1)
    175 {
    176     // Non-CSSValueList data is not accessible through CSS OM, no need to clone.
    177 }
    178 
    179 PassRefPtr<CSSImageSetValue> CSSImageSetValue::cloneForCSSOM() const
    180 {
    181     return adoptRef(new CSSImageSetValue(*this));
    182 }
    183 
    184 } // namespace WebCore
    185