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->setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
352 layer->setParentItem(view);
353 layer->setZValue(RootGraphicsLayerZValue);
354 }
355 createOrDeleteOverlay();
356 }
357 #endif
358
markForSync(bool scheduleSync)359 void PageClientQGraphicsWidget::markForSync(bool scheduleSync)
360 {
361 shouldSync = true;
362 if (scheduleSync)
363 syncMetaMethod.invoke(view, Qt::QueuedConnection);
364 }
365
366 #endif
367
368 #if ENABLE(TILED_BACKING_STORE)
updateTiledBackingStoreScale()369 void PageClientQGraphicsWidget::updateTiledBackingStoreScale()
370 {
371 WebCore::TiledBackingStore* backingStore = QWebFramePrivate::core(page->mainFrame())->tiledBackingStore();
372 if (!backingStore)
373 return;
374 backingStore->setContentsScale(view->scale());
375 }
376 #endif
377
setInputMethodEnabled(bool enable)378 void PageClientQGraphicsWidget::setInputMethodEnabled(bool enable)
379 {
380 view->setFlag(QGraphicsItem::ItemAcceptsInputMethod, enable);
381 }
382
inputMethodEnabled() const383 bool PageClientQGraphicsWidget::inputMethodEnabled() const
384 {
385 return view->flags() & QGraphicsItem::ItemAcceptsInputMethod;
386 }
387
setInputMethodHints(Qt::InputMethodHints hints)388 void PageClientQGraphicsWidget::setInputMethodHints(Qt::InputMethodHints hints)
389 {
390 view->setInputMethodHints(hints);
391 }
392
393 #ifndef QT_NO_CURSOR
cursor() const394 QCursor PageClientQGraphicsWidget::cursor() const
395 {
396 return view->cursor();
397 }
398
updateCursor(const QCursor & cursor)399 void PageClientQGraphicsWidget::updateCursor(const QCursor& cursor)
400 {
401 view->setCursor(cursor);
402 }
403 #endif
404
palette() const405 QPalette PageClientQGraphicsWidget::palette() const
406 {
407 return view->palette();
408 }
409
screenNumber() const410 int PageClientQGraphicsWidget::screenNumber() const
411 {
412 #if defined(Q_WS_X11)
413 if (QGraphicsScene* scene = view->scene()) {
414 const QList<QGraphicsView*> views = scene->views();
415
416 if (!views.isEmpty())
417 return views.at(0)->x11Info().screen();
418 }
419 #endif
420
421 return 0;
422 }
423
ownerWidget() const424 QWidget* PageClientQGraphicsWidget::ownerWidget() const
425 {
426 if (QGraphicsScene* scene = view->scene()) {
427 const QList<QGraphicsView*> views = scene->views();
428 return views.value(0);
429 }
430 return 0;
431 }
432
geometryRelativeToOwnerWidget() const433 QRect PageClientQGraphicsWidget::geometryRelativeToOwnerWidget() const
434 {
435 if (!view->scene())
436 return QRect();
437
438 QList<QGraphicsView*> views = view->scene()->views();
439 if (views.isEmpty())
440 return QRect();
441
442 QGraphicsView* graphicsView = views.at(0);
443 return graphicsView->mapFromScene(view->boundingRect()).boundingRect();
444 }
445
446 #if ENABLE(TILED_BACKING_STORE)
graphicsItemVisibleRect() const447 QRectF PageClientQGraphicsWidget::graphicsItemVisibleRect() const
448 {
449 if (!view->scene())
450 return QRectF();
451
452 QList<QGraphicsView*> views = view->scene()->views();
453 if (views.isEmpty())
454 return QRectF();
455
456 QGraphicsView* graphicsView = views.at(0);
457 int xOffset = graphicsView->horizontalScrollBar()->value();
458 int yOffset = graphicsView->verticalScrollBar()->value();
459 return view->mapRectFromScene(QRectF(QPointF(xOffset, yOffset), graphicsView->viewport()->size()));
460 }
461 #endif
462
pluginParent() const463 QObject* PageClientQGraphicsWidget::pluginParent() const
464 {
465 return view;
466 }
467
style() const468 QStyle* PageClientQGraphicsWidget::style() const
469 {
470 return view->style();
471 }
472
windowRect() const473 QRectF PageClientQGraphicsWidget::windowRect() const
474 {
475 if (!view->scene())
476 return QRectF();
477
478 // The sceneRect is a good approximation of the size of the application, independent of the view.
479 return view->scene()->sceneRect();
480 }
481 #endif // QT_NO_GRAPHICSVIEW
482
483 } // namespace WebCore
484