1/*
2 * Copyright (C) 2012 Adobe Systems Incorporated. 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 *
8 * 1. Redistributions of source code must retain the above
9 *    copyright notice, this list of conditions and the following
10 *    disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 *    copyright notice, this list of conditions and the following
13 *    disclaimer in the documentation and/or other materials
14 *    provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include "config.h"
31
32#if ENABLE(CSS_FILTERS)
33#include "RenderLayerFilterInfo.h"
34
35#include "FilterEffectRenderer.h"
36#include "RenderLayer.h"
37
38#if ENABLE(SVG)
39#include "CachedSVGDocument.h"
40#include "CachedSVGDocumentReference.h"
41#include "SVGElement.h"
42#include "SVGFilter.h"
43#include "SVGFilterPrimitiveStandardAttributes.h"
44#endif
45
46#if ENABLE(CSS_SHADERS)
47#include "CustomFilterOperation.h"
48#include "CustomFilterProgram.h"
49#endif
50
51namespace WebCore {
52
53RenderLayerFilterInfoMap* RenderLayerFilterInfo::s_filterMap = 0;
54
55RenderLayerFilterInfo* RenderLayerFilterInfo::filterInfoForRenderLayer(const RenderLayer* layer)
56{
57    if (!s_filterMap)
58        return 0;
59    RenderLayerFilterInfoMap::iterator iter = s_filterMap->find(layer);
60    return (iter != s_filterMap->end()) ? iter->value : 0;
61}
62
63RenderLayerFilterInfo* RenderLayerFilterInfo::createFilterInfoForRenderLayerIfNeeded(RenderLayer* layer)
64{
65    if (!s_filterMap)
66        s_filterMap = new RenderLayerFilterInfoMap();
67
68    RenderLayerFilterInfoMap::iterator iter = s_filterMap->find(layer);
69    if (iter != s_filterMap->end()) {
70        ASSERT(layer->hasFilterInfo());
71        return iter->value;
72    }
73
74    RenderLayerFilterInfo* filter = new RenderLayerFilterInfo(layer);
75    s_filterMap->set(layer, filter);
76    layer->setHasFilterInfo(true);
77    return filter;
78}
79
80void RenderLayerFilterInfo::removeFilterInfoForRenderLayer(RenderLayer* layer)
81{
82    if (!s_filterMap)
83        return;
84    RenderLayerFilterInfo* filter = s_filterMap->take(layer);
85    if (s_filterMap->isEmpty()) {
86        delete s_filterMap;
87        s_filterMap = 0;
88    }
89    if (!filter) {
90        ASSERT(!layer->hasFilterInfo());
91        return;
92    }
93    layer->setHasFilterInfo(false);
94    delete filter;
95}
96
97RenderLayerFilterInfo::RenderLayerFilterInfo(RenderLayer* layer)
98    : m_layer(layer)
99{
100}
101
102RenderLayerFilterInfo::~RenderLayerFilterInfo()
103{
104#if ENABLE(CSS_SHADERS)
105    removeCustomFilterClients();
106#endif
107#if ENABLE(SVG)
108    removeReferenceFilterClients();
109#endif
110}
111
112void RenderLayerFilterInfo::setRenderer(PassRefPtr<FilterEffectRenderer> renderer)
113{
114    m_renderer = renderer;
115}
116
117#if ENABLE(SVG)
118void RenderLayerFilterInfo::notifyFinished(CachedResource*)
119{
120    m_layer->filterNeedsRepaint();
121}
122
123void RenderLayerFilterInfo::updateReferenceFilterClients(const FilterOperations& operations)
124{
125    removeReferenceFilterClients();
126    for (size_t i = 0; i < operations.size(); ++i) {
127        RefPtr<FilterOperation> filterOperation = operations.operations().at(i);
128        if (filterOperation->getOperationType() != FilterOperation::REFERENCE)
129            continue;
130        ReferenceFilterOperation* referenceFilterOperation = toReferenceFilterOperation(filterOperation.get());
131        CachedSVGDocumentReference* documentReference = referenceFilterOperation->cachedSVGDocumentReference();
132        CachedSVGDocument* cachedSVGDocument = documentReference ? documentReference->document() : 0;
133
134        if (cachedSVGDocument) {
135            // Reference is external; wait for notifyFinished().
136            cachedSVGDocument->addClient(this);
137            m_externalSVGReferences.append(cachedSVGDocument);
138        } else {
139            // Reference is internal; add layer as a client so we can trigger
140            // filter repaint on SVG attribute change.
141            Element* filter = m_layer->renderer()->document()->getElementById(referenceFilterOperation->fragment());
142
143            if (!filter || !filter->renderer() || !filter->renderer()->isSVGResourceFilter())
144                continue;
145            filter->renderer()->toRenderSVGResourceContainer()->addClientRenderLayer(m_layer);
146            m_internalSVGReferences.append(filter);
147        }
148    }
149}
150
151void RenderLayerFilterInfo::removeReferenceFilterClients()
152{
153    for (size_t i = 0; i < m_externalSVGReferences.size(); ++i)
154        m_externalSVGReferences.at(i)->removeClient(this);
155    m_externalSVGReferences.clear();
156    for (size_t i = 0; i < m_internalSVGReferences.size(); ++i) {
157        Element* filter = m_internalSVGReferences.at(i).get();
158        if (!filter->renderer())
159            continue;
160        filter->renderer()->toRenderSVGResourceContainer()->removeClientRenderLayer(m_layer);
161    }
162    m_internalSVGReferences.clear();
163}
164#endif
165
166#if ENABLE(CSS_SHADERS)
167void RenderLayerFilterInfo::notifyCustomFilterProgramLoaded(CustomFilterProgram*)
168{
169    RenderObject* renderer = m_layer->renderer();
170    renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange);
171    renderer->repaint();
172}
173
174void RenderLayerFilterInfo::updateCustomFilterClients(const FilterOperations& operations)
175{
176    if (!operations.size()) {
177        removeCustomFilterClients();
178        return;
179    }
180    CustomFilterProgramList cachedCustomFilterPrograms;
181    for (size_t i = 0; i < operations.size(); ++i) {
182        const FilterOperation* filterOperation = operations.at(i);
183        if (filterOperation->getOperationType() != FilterOperation::CUSTOM)
184            continue;
185        const CustomFilterOperation* customFilterOperation = static_cast<const CustomFilterOperation*>(filterOperation);
186        RefPtr<CustomFilterProgram> program = customFilterOperation->program();
187        cachedCustomFilterPrograms.append(program);
188        program->addClient(this);
189    }
190    // Remove the old clients here, after we've added the new ones, so that we don't flicker if some shaders are unchanged.
191    removeCustomFilterClients();
192    m_cachedCustomFilterPrograms.swap(cachedCustomFilterPrograms);
193}
194
195void RenderLayerFilterInfo::removeCustomFilterClients()
196{
197    for (size_t i = 0; i < m_cachedCustomFilterPrograms.size(); ++i)
198        m_cachedCustomFilterPrograms.at(i)->removeClient(this);
199    m_cachedCustomFilterPrograms.clear();
200}
201#endif
202
203} // namespace WebCore
204
205#endif // ENABLE(CSS_FILTERS)
206