f5294755a233655c3066571cf639becb50c03050
[WebKit-https.git] / Source / WebCore / platform / graphics / texmap / coordinated / CoordinatedImageBacking.cpp
1 /*
2  * Copyright (C) 2012 Company 100, 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
28 #if USE(COORDINATED_GRAPHICS)
29 #include "CoordinatedImageBacking.h"
30
31 #include "CoordinatedGraphicsState.h"
32 #include "GraphicsContext.h"
33
34 namespace WebCore {
35
36 class ImageBackingSurfaceClient : public CoordinatedSurface::Client {
37 public:
38     ImageBackingSurfaceClient(Image& image, const IntRect& rect)
39         : m_image(image)
40         , m_rect(rect)
41     {
42     }
43
44     void paintToSurfaceContext(GraphicsContext& context) override
45     {
46         context.drawImage(m_image, m_rect, m_rect);
47     }
48
49 private:
50     Image& m_image;
51     IntRect m_rect;
52 };
53
54 CoordinatedImageBackingID CoordinatedImageBacking::getCoordinatedImageBackingID(Image* image)
55 {
56     // CoordinatedImageBacking keeps a RefPtr<Image> member, so the same Image pointer can not refer two different instances until CoordinatedImageBacking releases the member.
57     return reinterpret_cast<CoordinatedImageBackingID>(image);
58 }
59
60 PassRefPtr<CoordinatedImageBacking> CoordinatedImageBacking::create(Client* client, PassRefPtr<Image> image)
61 {
62     return adoptRef(new CoordinatedImageBacking(client, image));
63 }
64
65 CoordinatedImageBacking::CoordinatedImageBacking(Client* client, PassRefPtr<Image> image)
66     : m_client(client)
67     , m_image(image)
68     , m_id(getCoordinatedImageBackingID(m_image.get()))
69     , m_clearContentsTimer(*this, &CoordinatedImageBacking::clearContentsTimerFired)
70     , m_isDirty(false)
71     , m_isVisible(false)
72 {
73     // FIXME: We would need to decode a small image directly into a GraphicsSurface.
74     // http://webkit.org/b/101426
75
76     m_client->createImageBacking(id());
77 }
78
79 CoordinatedImageBacking::~CoordinatedImageBacking()
80 {
81 }
82
83 void CoordinatedImageBacking::addHost(Host* host)
84 {
85     ASSERT(!m_hosts.contains(host));
86     m_hosts.append(host);
87 }
88
89 void CoordinatedImageBacking::removeHost(Host* host)
90 {
91     size_t position = m_hosts.find(host);
92     ASSERT(position != notFound);
93     m_hosts.remove(position);
94
95     if (m_hosts.isEmpty())
96         m_client->removeImageBacking(id());
97 }
98
99 void CoordinatedImageBacking::markDirty()
100 {
101     m_isDirty = true;
102 }
103
104 void CoordinatedImageBacking::update()
105 {
106     releaseSurfaceIfNeeded();
107
108     bool changedToVisible;
109     updateVisibilityIfNeeded(changedToVisible);
110     if (!m_isVisible)
111         return;
112
113     if (!changedToVisible) {
114         if (!m_isDirty)
115             return;
116
117         if (m_nativeImagePtr == m_image->nativeImageForCurrentFrame()) {
118             m_isDirty = false;
119             return;
120         }
121     }
122
123     m_surface = CoordinatedSurface::create(IntSize(m_image->size()), !m_image->currentFrameKnownToBeOpaque() ? CoordinatedSurface::SupportsAlpha : CoordinatedSurface::NoFlags);
124     if (!m_surface) {
125         m_isDirty = false;
126         return;
127     }
128
129     IntRect rect(IntPoint::zero(), IntSize(m_image->size()));
130
131     ImageBackingSurfaceClient surfaceClient(*m_image, rect);
132     m_surface->paintToSurface(rect, surfaceClient);
133
134     m_nativeImagePtr = m_image->nativeImageForCurrentFrame();
135
136     m_client->updateImageBacking(id(), m_surface.copyRef());
137     m_isDirty = false;
138 }
139
140 void CoordinatedImageBacking::releaseSurfaceIfNeeded()
141 {
142     // We must keep m_surface until UI Process reads m_surface.
143     // If m_surface exists, it was created in the previous update.
144     m_surface = nullptr;
145 }
146
147 static const Seconds clearContentsTimerInterval { 3_s };
148
149 void CoordinatedImageBacking::updateVisibilityIfNeeded(bool& changedToVisible)
150 {
151     bool previousIsVisible = m_isVisible;
152
153     m_isVisible = false;
154     for (auto& host : m_hosts) {
155         if (host->imageBackingVisible()) {
156             m_isVisible = true;
157             break;
158         }
159     }
160
161     bool changedToInvisible = previousIsVisible && !m_isVisible;
162     if (changedToInvisible) {
163         ASSERT(!m_clearContentsTimer.isActive());
164         m_clearContentsTimer.startOneShot(clearContentsTimerInterval);
165     }
166
167     changedToVisible = !previousIsVisible && m_isVisible;
168
169     if (m_isVisible && m_clearContentsTimer.isActive()) {
170         m_clearContentsTimer.stop();
171         // We don't want to update the texture if we didn't remove the texture.
172         changedToVisible = false;
173     }
174 }
175
176 void CoordinatedImageBacking::clearContentsTimerFired()
177 {
178     m_client->clearImageBackingContents(id());
179 }
180
181 } // namespace WebCore
182 #endif