/* * Copyright (C) 2008, 2011, 2012, 2013 Apple Inc. All rights reserved. * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "CSSImageGeneratorValue.h" #include "CSSCanvasValue.h" #include "CSSCrossfadeValue.h" #include "CSSFilterImageValue.h" #include "CSSGradientValue.h" #include "CSSImageValue.h" #include "CSSNamedImageValue.h" #include "GeneratedImage.h" #include "RenderElement.h" #include "StyleCachedImage.h" namespace WebCore { static const auto timeToKeepCachedGeneratedImages = std::chrono::seconds { 3 }; CSSImageGeneratorValue::CSSImageGeneratorValue(ClassType classType) : CSSValue(classType) { } CSSImageGeneratorValue::~CSSImageGeneratorValue() { } void CSSImageGeneratorValue::addClient(RenderElement* renderer) { ASSERT(renderer); if (m_clients.isEmpty()) ref(); m_clients.add(renderer); } void CSSImageGeneratorValue::removeClient(RenderElement* renderer) { ASSERT(renderer); ASSERT(m_clients.contains(renderer)); if (m_clients.remove(renderer) && m_clients.isEmpty()) deref(); } GeneratedImage* CSSImageGeneratorValue::cachedImageForSize(FloatSize size) { if (size.isEmpty()) return nullptr; CachedGeneratedImage* cachedGeneratedImage = m_images.get(size); if (!cachedGeneratedImage) return nullptr; cachedGeneratedImage->puntEvictionTimer(); return cachedGeneratedImage->image(); } void CSSImageGeneratorValue::saveCachedImageForSize(FloatSize size, PassRefPtr image) { ASSERT(!m_images.contains(size)); m_images.add(size, std::make_unique(*this, size, image)); } void CSSImageGeneratorValue::evictCachedGeneratedImage(FloatSize size) { ASSERT(m_images.contains(size)); m_images.remove(size); } CSSImageGeneratorValue::CachedGeneratedImage::CachedGeneratedImage(CSSImageGeneratorValue& owner, FloatSize size, PassRefPtr image) : m_owner(owner) , m_size(size) , m_image(image) , m_evictionTimer(*this, &CSSImageGeneratorValue::CachedGeneratedImage::evictionTimerFired, timeToKeepCachedGeneratedImages) { m_evictionTimer.restart(); } void CSSImageGeneratorValue::CachedGeneratedImage::evictionTimerFired() { // NOTE: This is essentially a "delete this", the object is no longer valid after this line. m_owner.evictCachedGeneratedImage(m_size); } RefPtr CSSImageGeneratorValue::image(RenderElement* renderer, const FloatSize& size) { switch (classType()) { case CanvasClass: return downcast(*this).image(renderer, size); case NamedImageClass: return downcast(*this).image(renderer, size); case CrossfadeClass: return downcast(*this).image(renderer, size); case FilterImageClass: return downcast(*this).image(renderer, size); case LinearGradientClass: return downcast(*this).image(renderer, size); case RadialGradientClass: return downcast(*this).image(renderer, size); default: ASSERT_NOT_REACHED(); } return nullptr; } bool CSSImageGeneratorValue::isFixedSize() const { switch (classType()) { case CanvasClass: return downcast(*this).isFixedSize(); case NamedImageClass: return downcast(*this).isFixedSize(); case CrossfadeClass: return downcast(*this).isFixedSize(); case FilterImageClass: return downcast(*this).isFixedSize(); case LinearGradientClass: return downcast(*this).isFixedSize(); case RadialGradientClass: return downcast(*this).isFixedSize(); default: ASSERT_NOT_REACHED(); } return false; } FloatSize CSSImageGeneratorValue::fixedSize(const RenderElement* renderer) { switch (classType()) { case CanvasClass: return downcast(*this).fixedSize(renderer); case CrossfadeClass: return downcast(*this).fixedSize(renderer); case FilterImageClass: return downcast(*this).fixedSize(renderer); case LinearGradientClass: return downcast(*this).fixedSize(renderer); case RadialGradientClass: return downcast(*this).fixedSize(renderer); default: ASSERT_NOT_REACHED(); } return FloatSize(); } bool CSSImageGeneratorValue::isPending() const { switch (classType()) { case CrossfadeClass: return downcast(*this).isPending(); case CanvasClass: return downcast(*this).isPending(); case NamedImageClass: return downcast(*this).isPending(); case FilterImageClass: return downcast(*this).isPending(); case LinearGradientClass: return downcast(*this).isPending(); case RadialGradientClass: return downcast(*this).isPending(); default: ASSERT_NOT_REACHED(); } return false; } bool CSSImageGeneratorValue::knownToBeOpaque(const RenderElement* renderer) const { switch (classType()) { case CrossfadeClass: return downcast(*this).knownToBeOpaque(renderer); case CanvasClass: return false; case NamedImageClass: return false; case FilterImageClass: return downcast(*this).knownToBeOpaque(renderer); case LinearGradientClass: return downcast(*this).knownToBeOpaque(renderer); case RadialGradientClass: return downcast(*this).knownToBeOpaque(renderer); default: ASSERT_NOT_REACHED(); } return false; } void CSSImageGeneratorValue::loadSubimages(CachedResourceLoader& cachedResourceLoader, const ResourceLoaderOptions& options) { switch (classType()) { case CrossfadeClass: downcast(*this).loadSubimages(cachedResourceLoader, options); break; case CanvasClass: downcast(*this).loadSubimages(cachedResourceLoader, options); break; case FilterImageClass: downcast(*this).loadSubimages(cachedResourceLoader, options); break; case LinearGradientClass: downcast(*this).loadSubimages(cachedResourceLoader, options); break; case RadialGradientClass: downcast(*this).loadSubimages(cachedResourceLoader, options); break; default: ASSERT_NOT_REACHED(); } } bool CSSImageGeneratorValue::subimageIsPending(CSSValue* value) { if (is(*value)) return downcast(*value).cachedOrPendingImage()->isPendingImage(); if (is(*value)) return downcast(*value).isPending(); if (is(*value) && downcast(*value).getValueID() == CSSValueNone) return false; ASSERT_NOT_REACHED(); return false; } CachedImage* CSSImageGeneratorValue::cachedImageForCSSValue(CSSValue* value, CachedResourceLoader& cachedResourceLoader, const ResourceLoaderOptions& options) { if (!value) return nullptr; if (is(*value)) { StyleCachedImage* styleCachedImage = downcast(*value).cachedImage(cachedResourceLoader, options); if (!styleCachedImage) return nullptr; return styleCachedImage->cachedImage(); } if (is(*value)) { downcast(*value).loadSubimages(cachedResourceLoader, options); // FIXME: Handle CSSImageGeneratorValue (and thus cross-fades with gradients and canvas). return nullptr; } if (is(*value) && downcast(*value).getValueID() == CSSValueNone) return nullptr; ASSERT_NOT_REACHED(); return nullptr; } } // namespace WebCore