CSSImageSetValue.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /*
  2. * Copyright (C) 2012, 2013 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. #include "config.h"
  26. #include "CSSImageSetValue.h"
  27. #if ENABLE(CSS_IMAGE_SET)
  28. #include "CSSImageValue.h"
  29. #include "CSSPrimitiveValue.h"
  30. #include "CachedImage.h"
  31. #include "CachedResourceLoader.h"
  32. #include "CachedResourceRequest.h"
  33. #include "CachedResourceRequestInitiators.h"
  34. #include "Document.h"
  35. #include "Page.h"
  36. #include "StyleCachedImageSet.h"
  37. #include "StylePendingImage.h"
  38. #include <wtf/text/StringBuilder.h>
  39. namespace WebCore {
  40. CSSImageSetValue::CSSImageSetValue()
  41. : CSSValueList(ImageSetClass, CommaSeparator)
  42. , m_accessedBestFitImage(false)
  43. , m_scaleFactor(1)
  44. {
  45. }
  46. inline void CSSImageSetValue::detachPendingImage()
  47. {
  48. if (m_imageSet && m_imageSet->isPendingImage())
  49. static_cast<StylePendingImage&>(*m_imageSet).detachFromCSSValue();
  50. }
  51. CSSImageSetValue::~CSSImageSetValue()
  52. {
  53. detachPendingImage();
  54. if (m_imageSet && m_imageSet->isCachedImageSet())
  55. static_cast<StyleCachedImageSet*>(m_imageSet.get())->clearImageSetValue();
  56. }
  57. void CSSImageSetValue::fillImageSet()
  58. {
  59. size_t length = this->length();
  60. size_t i = 0;
  61. while (i < length) {
  62. CSSValue* imageValue = item(i);
  63. ASSERT_WITH_SECURITY_IMPLICATION(imageValue->isImageValue());
  64. String imageURL = static_cast<CSSImageValue*>(imageValue)->url();
  65. ++i;
  66. ASSERT_WITH_SECURITY_IMPLICATION(i < length);
  67. CSSValue* scaleFactorValue = item(i);
  68. ASSERT_WITH_SECURITY_IMPLICATION(scaleFactorValue->isPrimitiveValue());
  69. float scaleFactor = static_cast<CSSPrimitiveValue*>(scaleFactorValue)->getFloatValue();
  70. ImageWithScale image;
  71. image.imageURL = imageURL;
  72. image.scaleFactor = scaleFactor;
  73. m_imagesInSet.append(image);
  74. ++i;
  75. }
  76. // Sort the images so that they are stored in order from lowest resolution to highest.
  77. std::sort(m_imagesInSet.begin(), m_imagesInSet.end(), CSSImageSetValue::compareByScaleFactor);
  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. StyleCachedImageSet* CSSImageSetValue::cachedImageSet(CachedResourceLoader* loader)
  91. {
  92. ASSERT(loader);
  93. Document* document = loader->document();
  94. if (Page* page = document->page())
  95. m_scaleFactor = page->deviceScaleFactor();
  96. else
  97. m_scaleFactor = 1;
  98. if (!m_imagesInSet.size())
  99. fillImageSet();
  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. CachedResourceRequest request(ResourceRequest(document->completeURL(image.imageURL)));
  106. request.setInitiator(cachedResourceRequestInitiators().css);
  107. if (CachedResourceHandle<CachedImage> cachedImage = loader->requestImage(request)) {
  108. detachPendingImage();
  109. m_imageSet = StyleCachedImageSet::create(cachedImage.get(), image.scaleFactor, this);
  110. m_accessedBestFitImage = true;
  111. }
  112. }
  113. return (m_imageSet && m_imageSet->isCachedImageSet()) ? static_cast<StyleCachedImageSet*>(m_imageSet.get()) : 0;
  114. }
  115. StyleImage* CSSImageSetValue::cachedOrPendingImageSet(Document* document)
  116. {
  117. if (!m_imageSet)
  118. m_imageSet = StylePendingImage::create(this);
  119. else if (document && !m_imageSet->isPendingImage()) {
  120. float deviceScaleFactor = 1;
  121. if (Page* page = document->page())
  122. deviceScaleFactor = page->deviceScaleFactor();
  123. // If the deviceScaleFactor has changed, we may not have the best image loaded, so we have to re-assess.
  124. if (deviceScaleFactor != m_scaleFactor) {
  125. m_accessedBestFitImage = false;
  126. m_imageSet = StylePendingImage::create(this);
  127. }
  128. }
  129. return m_imageSet.get();
  130. }
  131. String CSSImageSetValue::customCssText() const
  132. {
  133. StringBuilder result;
  134. result.appendLiteral("-webkit-image-set(");
  135. size_t length = this->length();
  136. size_t i = 0;
  137. while (i < length) {
  138. if (i > 0)
  139. result.appendLiteral(", ");
  140. const CSSValue* imageValue = item(i);
  141. result.append(imageValue->cssText());
  142. result.append(' ');
  143. ++i;
  144. ASSERT_WITH_SECURITY_IMPLICATION(i < length);
  145. const CSSValue* scaleFactorValue = item(i);
  146. result.append(scaleFactorValue->cssText());
  147. // FIXME: Eventually the scale factor should contain it's own unit http://wkb.ug/100120.
  148. // For now 'x' is hard-coded in the parser, so we hard-code it here too.
  149. result.append('x');
  150. ++i;
  151. }
  152. result.append(')');
  153. return result.toString();
  154. }
  155. bool CSSImageSetValue::hasFailedOrCanceledSubresources() const
  156. {
  157. if (!m_imageSet || !m_imageSet->isCachedImageSet())
  158. return false;
  159. CachedResource* cachedResource = static_cast<StyleCachedImageSet*>(m_imageSet.get())->cachedImage();
  160. if (!cachedResource)
  161. return true;
  162. return cachedResource->loadFailedOrCanceled();
  163. }
  164. CSSImageSetValue::CSSImageSetValue(const CSSImageSetValue& cloneFrom)
  165. : CSSValueList(cloneFrom)
  166. , m_accessedBestFitImage(false)
  167. , m_scaleFactor(1)
  168. {
  169. // Non-CSSValueList data is not accessible through CSS OM, no need to clone.
  170. }
  171. PassRefPtr<CSSImageSetValue> CSSImageSetValue::cloneForCSSOM() const
  172. {
  173. return adoptRef(new CSSImageSetValue(*this));
  174. }
  175. } // namespace WebCore
  176. #endif // ENABLE(CSS_IMAGE_SET)