1 /*
2  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  *
19  */
20 
21 #include "config.h"
22 
23 #include "PageClientQt.h"
24 #include "TextureMapperQt.h"
25 #include "texmap/TextureMapperPlatformLayer.h"
26 #include <QGraphicsScene>
27 #include <QGraphicsView>
28 #if defined(Q_WS_X11)
29 #include <QX11Info>
30 #endif
31 
32 #ifdef QT_OPENGL_LIB
33 #include "opengl/TextureMapperGL.h"
34 #include <QGLWidget>
35 #endif
36 
37 namespace WebCore {
38 
39 #if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER)
40 class PlatformLayerProxyQt : public QObject, public virtual TextureMapperLayerClient {
41 public:
PlatformLayerProxyQt(QWebFrame * frame,TextureMapperContentLayer * layer,QObject * object)42     PlatformLayerProxyQt(QWebFrame* frame, TextureMapperContentLayer* layer, QObject* object)
43         : QObject(object)
44         , m_frame(frame)
45         , m_layer(layer)
46     {
47         if (m_layer)
48             m_layer->setPlatformLayerClient(this);
49         m_frame->d->rootGraphicsLayer = m_layer;
50     }
51 
setTextureMapper(PassOwnPtr<TextureMapper> textureMapper)52     void setTextureMapper(PassOwnPtr<TextureMapper> textureMapper)
53     {
54         m_frame->d->textureMapper = textureMapper;
55     }
56 
~PlatformLayerProxyQt()57     virtual ~PlatformLayerProxyQt()
58     {
59         if (m_layer)
60             m_layer->setPlatformLayerClient(0);
61         if (m_frame->d)
62             m_frame->d->rootGraphicsLayer = 0;
63     }
64 
textureMapper()65     virtual TextureMapper* textureMapper()
66     {
67         return m_frame->d->textureMapper.get();
68     }
69 
70     // Since we just paint the composited tree and never create a special item for it, we don't have to handle its size changes.
setSizeChanged(const IntSize &)71     void setSizeChanged(const IntSize&) { }
72 
73 private:
74     QWebFrame* m_frame;
75     TextureMapperContentLayer* m_layer;
76 };
77 
78 class PlatformLayerProxyQWidget : public PlatformLayerProxyQt {
79 public:
PlatformLayerProxyQWidget(QWebFrame * frame,TextureMapperContentLayer * layer,QWidget * widget)80     PlatformLayerProxyQWidget(QWebFrame* frame, TextureMapperContentLayer* layer, QWidget* widget)
81         : PlatformLayerProxyQt(frame, layer, widget)
82         , m_widget(widget)
83     {
84         if (m_widget)
85             m_widget->installEventFilter(this);
86 
87         if (textureMapper())
88             return;
89 
90         setTextureMapper(TextureMapperQt::create());
91     }
92 
93     // We don't want a huge region-clip on the compositing layers; instead we unite the rectangles together
94     // and clear them when the paint actually occurs.
eventFilter(QObject * object,QEvent * event)95     bool eventFilter(QObject* object, QEvent* event)
96     {
97         if (object == m_widget && event->type() == QEvent::Paint)
98             m_dirtyRect = QRect();
99         return QObject::eventFilter(object, event);
100     }
101 
setNeedsDisplay()102     void setNeedsDisplay()
103     {
104         if (m_widget)
105             m_widget->update();
106     }
107 
setNeedsDisplayInRect(const IntRect & rect)108     void setNeedsDisplayInRect(const IntRect& rect)
109     {
110         m_dirtyRect |= rect;
111         m_widget->update(m_dirtyRect);
112     }
113 
114 private:
115     QRect m_dirtyRect;
116     QWidget* m_widget;
117 };
118 
119 #if !defined(QT_NO_GRAPHICSVIEW)
120 class PlatformLayerProxyQGraphicsObject : public PlatformLayerProxyQt {
121 public:
PlatformLayerProxyQGraphicsObject(QWebFrame * frame,TextureMapperContentLayer * layer,QGraphicsObject * object)122     PlatformLayerProxyQGraphicsObject(QWebFrame* frame, TextureMapperContentLayer* layer, QGraphicsObject* object)
123         : PlatformLayerProxyQt(frame, layer, object)
124         , m_graphicsItem(object)
125     {
126         if (textureMapper())
127             return;
128 
129 #ifdef QT_OPENGL_LIB
130         QGraphicsView* view = object->scene()->views()[0];
131         if (view && view->viewport() && view->viewport()->inherits("QGLWidget")) {
132             setTextureMapper(TextureMapperGL::create());
133             return;
134         }
135 #endif
136         setTextureMapper(TextureMapperQt::create());
137     }
138 
setNeedsDisplay()139     void setNeedsDisplay()
140     {
141         if (m_graphicsItem)
142             m_graphicsItem->update();
143     }
144 
setNeedsDisplayInRect(const IntRect & rect)145     void setNeedsDisplayInRect(const IntRect& rect)
146     {
147         if (m_graphicsItem)
148             m_graphicsItem->update(QRectF(rect));
149     }
150 
151 private:
152     QGraphicsItem* m_graphicsItem;
153 };
154 #endif // QT_NO_GRAPHICSVIEW
155 
setRootGraphicsLayer(TextureMapperPlatformLayer * layer)156 void PageClientQWidget::setRootGraphicsLayer(TextureMapperPlatformLayer* layer)
157 {
158     if (layer) {
159         platformLayerProxy = new PlatformLayerProxyQWidget(page->mainFrame(), static_cast<TextureMapperContentLayer*>(layer), view);
160         return;
161     }
162     delete platformLayerProxy;
163     platformLayerProxy = 0;
164 }
165 
markForSync(bool scheduleSync)166 void PageClientQWidget::markForSync(bool scheduleSync)
167 {
168     syncTimer.startOneShot(0);
169 }
170 
syncLayers(Timer<PageClientQWidget> *)171 void PageClientQWidget::syncLayers(Timer<PageClientQWidget>*)
172 {
173     QWebFramePrivate::core(page->mainFrame())->view()->syncCompositingStateIncludingSubframes();
174 }
175 #endif
176 
scroll(int dx,int dy,const QRect & rectToScroll)177 void PageClientQWidget::scroll(int dx, int dy, const QRect& rectToScroll)
178 {
179     view->scroll(qreal(dx), qreal(dy), rectToScroll);
180 }
181 
update(const QRect & dirtyRect)182 void PageClientQWidget::update(const QRect & dirtyRect)
183 {
184     view->update(dirtyRect);
185 }
186 
setInputMethodEnabled(bool enable)187 void PageClientQWidget::setInputMethodEnabled(bool enable)
188 {
189     view->setAttribute(Qt::WA_InputMethodEnabled, enable);
190 }
191 
inputMethodEnabled() const192 bool PageClientQWidget::inputMethodEnabled() const
193 {
194     return view->testAttribute(Qt::WA_InputMethodEnabled);
195 }
196 
setInputMethodHints(Qt::InputMethodHints hints)197 void PageClientQWidget::setInputMethodHints(Qt::InputMethodHints hints)
198 {
199     view->setInputMethodHints(hints);
200 }
201 
~PageClientQWidget()202 PageClientQWidget::~PageClientQWidget()
203 {
204 #if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER)
205     delete platformLayerProxy;
206 #endif
207 }
208 
209 #ifndef QT_NO_CURSOR
cursor() const210 QCursor PageClientQWidget::cursor() const
211 {
212     return view->cursor();
213 }
214 
updateCursor(const QCursor & cursor)215 void PageClientQWidget::updateCursor(const QCursor& cursor)
216 {
217     view->setCursor(cursor);
218 }
219 #endif
220 
palette() const221 QPalette PageClientQWidget::palette() const
222 {
223     return view->palette();
224 }
225 
screenNumber() const226 int PageClientQWidget::screenNumber() const
227 {
228 #if defined(Q_WS_X11)
229     return view->x11Info().screen();
230 #endif
231     return 0;
232 }
233 
ownerWidget() const234 QWidget* PageClientQWidget::ownerWidget() const
235 {
236     return view;
237 }
238 
geometryRelativeToOwnerWidget() const239 QRect PageClientQWidget::geometryRelativeToOwnerWidget() const
240 {
241     return view->geometry();
242 }
243 
pluginParent() const244 QObject* PageClientQWidget::pluginParent() const
245 {
246     return view;
247 }
248 
style() const249 QStyle* PageClientQWidget::style() const
250 {
251     return view->style();
252 }
253 
windowRect() const254 QRectF PageClientQWidget::windowRect() const
255 {
256     return QRectF(view->window()->geometry());
257 }
258 
259 #if !defined(QT_NO_GRAPHICSVIEW)
~PageClientQGraphicsWidget()260 PageClientQGraphicsWidget::~PageClientQGraphicsWidget()
261 {
262     delete overlay;
263 #if USE(ACCELERATED_COMPOSITING)
264 #if USE(TEXTURE_MAPPER)
265     delete platformLayerProxy;
266 #else
267     if (!rootGraphicsLayer)
268         return;
269     // we don't need to delete the root graphics layer. The lifecycle is managed in GraphicsLayerQt.cpp.
270     rootGraphicsLayer.data()->setParentItem(0);
271     view->scene()->removeItem(rootGraphicsLayer.data());
272 #endif
273 #endif
274 }
275 
scroll(int dx,int dy,const QRect & rectToScroll)276 void PageClientQGraphicsWidget::scroll(int dx, int dy, const QRect& rectToScroll)
277 {
278     view->scroll(qreal(dx), qreal(dy), rectToScroll);
279 }
280 
update(const QRect & dirtyRect)281 void PageClientQGraphicsWidget::update(const QRect& dirtyRect)
282 {
283     view->update(dirtyRect);
284 
285     createOrDeleteOverlay();
286     if (overlay)
287         overlay->update(QRectF(dirtyRect));
288 #if USE(ACCELERATED_COMPOSITING)
289     syncLayers();
290 #endif
291 }
292 
createOrDeleteOverlay()293 void PageClientQGraphicsWidget::createOrDeleteOverlay()
294 {
295     // We don't use an overlay with TextureMapper. Instead, the overlay is drawn inside QWebFrame.
296 #if !USE(TEXTURE_MAPPER)
297     bool useOverlay = false;
298     if (!viewResizesToContents) {
299 #if USE(ACCELERATED_COMPOSITING)
300         useOverlay = useOverlay || rootGraphicsLayer;
301 #endif
302 #if ENABLE(TILED_BACKING_STORE)
303         useOverlay = useOverlay || QWebFramePrivate::core(page->mainFrame())->tiledBackingStore();
304 #endif
305     }
306     if (useOverlay == !!overlay)
307         return;
308 
309     if (useOverlay) {
310         overlay = new QGraphicsItemOverlay(view, page);
311         overlay->setZValue(OverlayZValue);
312     } else {
313         // Changing the overlay might be done inside paint events.
314         overlay->deleteLater();
315         overlay = 0;
316     }
317 #endif // !USE(TEXTURE_MAPPER)
318 }
319 
320 #if USE(ACCELERATED_COMPOSITING)
syncLayers()321 void PageClientQGraphicsWidget::syncLayers()
322 {
323     if (shouldSync) {
324         QWebFramePrivate::core(page->mainFrame())->view()->syncCompositingStateIncludingSubframes();
325         shouldSync = false;
326     }
327 }
328 
329 #if USE(TEXTURE_MAPPER)
setRootGraphicsLayer(TextureMapperPlatformLayer * layer)330 void PageClientQGraphicsWidget::setRootGraphicsLayer(TextureMapperPlatformLayer* layer)
331 {
332     if (layer) {
333         platformLayerProxy = new PlatformLayerProxyQGraphicsObject(page->mainFrame(), static_cast<TextureMapperContentLayer*>(layer), view);
334         return;
335     }
336     delete platformLayerProxy;
337     platformLayerProxy = 0;
338 }
339 #else
setRootGraphicsLayer(QGraphicsObject * layer)340 void PageClientQGraphicsWidget::setRootGraphicsLayer(QGraphicsObject* layer)
341 {
342     if (rootGraphicsLayer) {
343         rootGraphicsLayer.data()->setParentItem(0);
344         view->scene()->removeItem(rootGraphicsLayer.data());
345         QWebFramePrivate::core(page->mainFrame())->view()->syncCompositingStateIncludingSubframes();
346     }
347 
348     rootGraphicsLayer = layer;
349 
350     if (layer) {
351         layer->setParentItem(view);
352         layer->setZValue(RootGraphicsLayerZValue);
353     }
354     createOrDeleteOverlay();
355 }
356 #endif
357 
markForSync(bool scheduleSync)358 void PageClientQGraphicsWidget::markForSync(bool scheduleSync)
359 {
360     shouldSync = true;
361     if (scheduleSync)
362         syncMetaMethod.invoke(view, Qt::QueuedConnection);
363 }
364 
365 #endif
366 
367 #if ENABLE(TILED_BACKING_STORE)
updateTiledBackingStoreScale()368 void PageClientQGraphicsWidget::updateTiledBackingStoreScale()
369 {
370     WebCore::TiledBackingStore* backingStore = QWebFramePrivate::core(page->mainFrame())->tiledBackingStore();
371     if (!backingStore)
372         return;
373     backingStore->setContentsScale(view->scale());
374 }
375 #endif
376 
setInputMethodEnabled(bool enable)377 void PageClientQGraphicsWidget::setInputMethodEnabled(bool enable)
378 {
379     view->setFlag(QGraphicsItem::ItemAcceptsInputMethod, enable);
380 }
381 
inputMethodEnabled() const382 bool PageClientQGraphicsWidget::inputMethodEnabled() const
383 {
384     return view->flags() & QGraphicsItem::ItemAcceptsInputMethod;
385 }
386 
setInputMethodHints(Qt::InputMethodHints hints)387 void PageClientQGraphicsWidget::setInputMethodHints(Qt::InputMethodHints hints)
388 {
389     view->setInputMethodHints(hints);
390 }
391 
392 #ifndef QT_NO_CURSOR
cursor() const393 QCursor PageClientQGraphicsWidget::cursor() const
394 {
395     return view->cursor();
396 }
397 
updateCursor(const QCursor & cursor)398 void PageClientQGraphicsWidget::updateCursor(const QCursor& cursor)
399 {
400     view->setCursor(cursor);
401 }
402 #endif
403 
palette() const404 QPalette PageClientQGraphicsWidget::palette() const
405 {
406     return view->palette();
407 }
408 
screenNumber() const409 int PageClientQGraphicsWidget::screenNumber() const
410 {
411 #if defined(Q_WS_X11)
412     if (QGraphicsScene* scene = view->scene()) {
413         const QList<QGraphicsView*> views = scene->views();
414 
415         if (!views.isEmpty())
416             return views.at(0)->x11Info().screen();
417     }
418 #endif
419 
420     return 0;
421 }
422 
ownerWidget() const423 QWidget* PageClientQGraphicsWidget::ownerWidget() const
424 {
425     if (QGraphicsScene* scene = view->scene()) {
426         const QList<QGraphicsView*> views = scene->views();
427         return views.value(0);
428     }
429     return 0;
430 }
431 
geometryRelativeToOwnerWidget() const432 QRect PageClientQGraphicsWidget::geometryRelativeToOwnerWidget() const
433 {
434     if (!view->scene())
435         return QRect();
436 
437     QList<QGraphicsView*> views = view->scene()->views();
438     if (views.isEmpty())
439         return QRect();
440 
441     QGraphicsView* graphicsView = views.at(0);
442     return graphicsView->mapFromScene(view->boundingRect()).boundingRect();
443 }
444 
445 #if ENABLE(TILED_BACKING_STORE)
graphicsItemVisibleRect() const446 QRectF PageClientQGraphicsWidget::graphicsItemVisibleRect() const
447 {
448     if (!view->scene())
449         return QRectF();
450 
451     QList<QGraphicsView*> views = view->scene()->views();
452     if (views.isEmpty())
453         return QRectF();
454 
455     QGraphicsView* graphicsView = views.at(0);
456     int xOffset = graphicsView->horizontalScrollBar()->value();
457     int yOffset = graphicsView->verticalScrollBar()->value();
458     return view->mapRectFromScene(QRectF(QPointF(xOffset, yOffset), graphicsView->viewport()->size()));
459 }
460 #endif
461 
pluginParent() const462 QObject* PageClientQGraphicsWidget::pluginParent() const
463 {
464     return view;
465 }
466 
style() const467 QStyle* PageClientQGraphicsWidget::style() const
468 {
469     return view->style();
470 }
471 
windowRect() const472 QRectF PageClientQGraphicsWidget::windowRect() const
473 {
474     if (!view->scene())
475         return QRectF();
476 
477     // The sceneRect is a good approximation of the size of the application, independent of the view.
478     return view->scene()->sceneRect();
479 }
480 #endif // QT_NO_GRAPHICSVIEW
481 
482 } // namespace WebCore
483