diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2013-06-03 13:12:48 +0000 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-06-06 13:02:46 +0200 |
commit | f64d11fc6fd0798fae2a1ecc7565b9d2efd385bc (patch) | |
tree | 712048665265ec820f9f5712f6841f6805e12bf6 | |
parent | 57626c5f3624b3b55d3b5a49118bca8a5baad8b3 (diff) | |
download | qtwebkit-f64d11fc6fd0798fae2a1ecc7565b9d2efd385bc.tar.gz |
[Qt][Mac] Allow drawing plugins with QWindow by always using an intermediate bitmap.
https://bugs.webkit.org/show_bug.cgi?id=116620
Reviewed by Tor Arne Vestbø.
The isolation of QWidget along with QPA in Qt5 is abstracting away the native CGContext
of a QWidget and we would need to create a non-public API to be able to achieve it.
Instead of adding complexity to this rarely touched code, always draw into an
intermediate bitmap that we then paint into our QPainter afterward.
- Use CGBitmapContextCreate to allocate a buffer directly instead of creating a QPixmap
and extract an CGContextRef out of it.
- Get rid of the "if (platformPluginWidget())" code path since we don't paint directly
into the QWidget's backing store anymore.
- Always use m_contextRef to draw the plugin instead of alternating between direct and
indirect drawing.
* plugins/PluginView.cpp:
(WebCore::PluginView::PluginView):
* plugins/PluginView.h:
* plugins/mac/PluginViewMac.mm:
(WebCore::createBitmapContext):
(WebCore::PluginView::platformStart):
(WebCore::PluginView::platformDestroy):
(WebCore::PluginView::setFocus):
(WebCore::PluginView::setNPWindowIfNeeded):
(WebCore::PluginView::updatePluginWidget):
(WebCore::PluginView::paint):
(WebCore::PluginView::invalidateRect):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@151107 268f45cc-cd09-0410-ab3c-d52691b4dbfc
Conflicts:
Source/WebCore/plugins/PluginView.h
Source/WebCore/plugins/mac/PluginViewMac.mm
Change-Id: I1006dcf3c08c14ca0d144532372de33f815fbc23
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
-rw-r--r-- | Source/WebCore/plugins/PluginView.cpp | 2 | ||||
-rw-r--r-- | Source/WebCore/plugins/PluginView.h | 9 | ||||
-rw-r--r-- | Source/WebCore/plugins/mac/PluginViewMac.mm | 228 |
3 files changed, 51 insertions, 188 deletions
diff --git a/Source/WebCore/plugins/PluginView.cpp b/Source/WebCore/plugins/PluginView.cpp index 861372f9d..cdf8a78bb 100644 --- a/Source/WebCore/plugins/PluginView.cpp +++ b/Source/WebCore/plugins/PluginView.cpp @@ -847,7 +847,7 @@ PluginView::PluginView(Frame* parentFrame, const IntSize& size, PluginPackage* p , m_wmPrintHDC(0) , m_haveUpdatedPluginWidget(false) #endif -#if (PLATFORM(QT) && OS(WINDOWS)) || defined(XP_MACOSX) || PLATFORM(EFL) +#if (PLATFORM(QT) && OS(WINDOWS)) || PLATFORM(EFL) , m_window(0) #endif #if defined(XP_MACOSX) diff --git a/Source/WebCore/plugins/PluginView.h b/Source/WebCore/plugins/PluginView.h index 821c16161..361c286db 100644 --- a/Source/WebCore/plugins/PluginView.h +++ b/Source/WebCore/plugins/PluginView.h @@ -52,9 +52,6 @@ typedef struct HWND__* HWND; typedef HWND PlatformPluginWidget; #else typedef PlatformWidget PlatformPluginWidget; -#if defined(XP_MACOSX) && PLATFORM(QT) -#include <QPixmap> -#endif #endif #if PLATFORM(QT) #if USE(TEXTURE_MAPPER) @@ -330,7 +327,6 @@ namespace WebCore { int16_t dispatchNPCocoaEvent(NPCocoaEvent&); bool m_updatedCocoaTextInputRequested; bool m_keyDownSent; - bool m_usePixmap; uint16_t m_disregardKeyUpCounter; #endif @@ -390,7 +386,7 @@ namespace WebCore { bool m_haveUpdatedPluginWidget; #endif -#if ((PLATFORM(GTK) || PLATFORM(QT) || PLATFORM(WX)) && OS(WINDOWS)) || defined(XP_MACOSX) || PLATFORM(EFL) +#if ((PLATFORM(GTK) || PLATFORM(QT) || PLATFORM(WX)) && OS(WINDOWS)) || PLATFORM(EFL) // On Mac OSX and Qt/Windows the plugin does not have its own native widget, // but is using the containing window as its reference for positioning/painting. PlatformPluginWidget m_window; @@ -410,9 +406,6 @@ private: #elif defined(XP_MACOSX) NP_CGContext m_npCgContext; CGContextRef m_contextRef; -#if PLATFORM(QT) - QPixmap m_pixmap; -#endif void setNPWindowIfNeeded(); #endif diff --git a/Source/WebCore/plugins/mac/PluginViewMac.mm b/Source/WebCore/plugins/mac/PluginViewMac.mm index e70d5eee6..d1582d837 100644 --- a/Source/WebCore/plugins/mac/PluginViewMac.mm +++ b/Source/WebCore/plugins/mac/PluginViewMac.mm @@ -73,16 +73,7 @@ using JSC::JSObject; using JSC::JSValue; #if PLATFORM(QT) -#include <QWidget> -#include <QKeyEvent> #include <QPainter> -#include <QDateTime> -#include <QPixmap> -#include "QWebPageClient.h" -QT_BEGIN_NAMESPACE -extern Q_GUI_EXPORT OSWindowRef qt_mac_window_for(const QWidget* w); -extern Q_GUI_EXPORT CGContextRef qt_mac_cg_context(const QPaintDevice *pdev); //qpaintdevice_mac.cpp -QT_END_NAMESPACE #endif #if PLATFORM(WX) @@ -96,52 +87,6 @@ namespace WebCore { using namespace HTMLNames; -static inline WindowRef nativeWindowFor(PlatformWidget widget) -{ -#if PLATFORM(QT) - if (widget) -#if QT_MAC_USE_COCOA - return static_cast<WindowRef>([qt_mac_window_for(static_cast<QWidget*>(widget)) windowRef]); -#else - return static_cast<WindowRef>(qt_mac_window_for(widget)); -#endif -#elif PLATFORM(WX) - if (widget) - return (WindowRef)widget->MacGetTopLevelWindowRef(); -#endif - return 0; -} - -static inline CGContextRef cgHandleFor(PlatformWidget widget) -{ -#if PLATFORM(QT) - if (widget) - return (CGContextRef)static_cast<QWidget*>(widget)->macCGHandle(); -#endif -#if PLATFORM(WX) - if (widget) - return (CGContextRef)widget->MacGetCGContextRef(); -#endif - return 0; -} - -static inline IntPoint topLevelOffsetFor(PlatformWidget widget) -{ -#if PLATFORM(QT) - if (widget) { - QWidget* topLevel = static_cast<QWidget*>(widget)->window(); - return static_cast<QWidget*>(widget)->mapTo(topLevel, QPoint(0, 0)) + topLevel->geometry().topLeft() - topLevel->pos(); - } -#endif -#if PLATFORM(WX) - if (widget) { - PlatformWidget toplevel = wxGetTopLevelParent(widget); - return toplevel->ScreenToClient(widget->GetScreenPosition()); - } -#endif - return IntPoint(); -} - // --------- Cocoa specific utility functions ---------- static void initializeNPCocoaEvent(NPCocoaEvent* event) @@ -161,6 +106,19 @@ static int32_t getModifiers(UIEventWithKeyState *event) return modifiers; } +static CGContextRef createBitmapContext(const IntSize& size) +{ + CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); + uint flags = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; + CGContextRef context = CGBitmapContextCreate(0, size.width(), size.height(), + 8, 4 * size.width(), colorspace, flags); + + CGContextTranslateCTM(context, 0, size.height()); + CGContextScaleCTM(context, 1, -1); + CGColorSpaceRelease(colorspace); + return context; +} + // --------------- Lifetime management ----------------- bool PluginView::platformStart() @@ -179,20 +137,6 @@ bool PluginView::platformStart() return false; } - -#if PLATFORM(QT) - // Set the platformPluginWidget only in the case of QWebView so that the context menu appears in the right place. - // In all other cases, we use off-screen rendering - if (QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient()) { - if (QWidget* widget = qobject_cast<QWidget*>(client->pluginParent())) - setPlatformPluginWidget(widget); - } -#endif -#if PLATFORM(WX) - if (wxWindow* widget = m_parentFrame->view()->hostWindow()->platformPageClient()) - setPlatformPluginWidget(widget); -#endif - updatePluginWidget(); if (!m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall)) @@ -203,11 +147,7 @@ bool PluginView::platformStart() void PluginView::platformDestroy() { - if (platformPluginWidget()) - setPlatformPluginWidget(0); - else { - CGContextRelease(m_contextRef); - } + CGContextRelease(m_contextRef); } // Used before the plugin view has been initialized properly, and as a @@ -308,15 +248,7 @@ void PluginView::setFocus(bool focused) if (!focused) Widget::setFocus(focused); - if (platformPluginWidget()) -#if PLATFORM(QT) - static_cast<QWidget*>(platformPluginWidget())->setFocus(Qt::OtherFocusReason); -#else - platformPluginWidget()->SetFocus(); -#endif - else - Widget::setFocus(focused); - + Widget::setFocus(focused); NPCocoaEvent cocoaEvent; initializeNPCocoaEvent(&cocoaEvent); @@ -344,32 +276,19 @@ void PluginView::setNPWindowRect(const IntRect&) void PluginView::setNPWindowIfNeeded() { - if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow) + if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow || !m_contextRef) return; - CGContextRef newContextRef = 0; - if (platformPluginWidget()) { - newContextRef = cgHandleFor(platformPluginWidget()); - m_npWindow.type = NPWindowTypeWindow; - } else { - newContextRef = m_contextRef; - m_npWindow.type = NPWindowTypeDrawable; - } - - if (!newContextRef) { - if (!m_usePixmap) - return; - } - + // The context is set through the draw event. + ASSERT(!m_npCgContext.context && !m_npCgContext.window); m_npWindow.window = (void*)&m_npCgContext; - m_npCgContext.context = newContextRef; + m_npWindow.type = NPWindowTypeDrawable; m_npWindow.x = m_windowRect.x(); m_npWindow.y = m_windowRect.y(); m_npWindow.width = m_windowRect.width(); m_npWindow.height = m_windowRect.height(); - // TODO: (also clip against scrollbars, etc.) m_npWindow.clipRect.left = max(0, m_windowRect.x()); m_npWindow.clipRect.top = max(0, m_windowRect.y()); m_npWindow.clipRect.right = m_windowRect.x() + m_windowRect.width(); @@ -377,7 +296,7 @@ void PluginView::setNPWindowIfNeeded() LOG(Plugins, "PluginView::setNPWindowIfNeeded(): context=%p," " window.x:%d window.y:%d window.width:%d window.height:%d window.clipRect size:%dx%d", - newContextRef, m_npWindow.x, m_npWindow.y, m_npWindow.width, m_npWindow.height, + m_contextRef, m_npWindow.x, m_npWindow.y, m_npWindow.width, m_npWindow.height, m_npWindow.clipRect.right - m_npWindow.clipRect.left, m_npWindow.clipRect.bottom - m_npWindow.clipRect.top); PluginView::setCurrentPluginView(this); @@ -397,27 +316,15 @@ void PluginView::updatePluginWidget() FrameView* frameView = static_cast<FrameView*>(parent()); IntRect oldWindowRect = m_windowRect; - IntRect oldClipRect = m_clipRect; - m_windowRect = frameView->contentsToWindow(frameRect()); - IntPoint offset = topLevelOffsetFor(platformPluginWidget()); - m_windowRect.move(offset.x(), offset.y()); - if (!platformPluginWidget()) { - if (m_windowRect.size() != oldWindowRect.size()) { - CGContextRelease(m_contextRef); -#if PLATFORM(QT) - m_pixmap = QPixmap(m_windowRect.size()); - m_pixmap.fill(Qt::transparent); - m_contextRef = m_pixmap.isNull() ? 0 : qt_mac_cg_context(&m_pixmap); -#endif - } + if (m_windowRect.size() != oldWindowRect.size()) { + CGContextRelease(m_contextRef); + m_contextRef = createBitmapContext(m_windowRect.size()); + CGContextClearRect(m_contextRef, CGRectMake(0, 0, m_windowRect.width(), m_windowRect.height())); } - m_clipRect = windowClipRect(); - m_clipRect.move(-m_windowRect.x(), -m_windowRect.y()); - - if (platformPluginWidget() && (m_windowRect != oldWindowRect || m_clipRect != oldClipRect)) + if (m_windowRect != oldWindowRect) setNPWindowIfNeeded(); } @@ -428,41 +335,10 @@ void PluginView::paint(GraphicsContext* context, const IntRect& rect) return; } - if (context->paintingDisabled()) + if (context->paintingDisabled() || !m_contextRef) return; -#if PLATFORM(QT) - QPainter* p = context->platformContext(); - CGContextRef cgContext = qt_mac_cg_context(p->device()); -#else - CGContextRef cgContext = m_npCgContext.context; -#endif - setNPWindowIfNeeded(); - if (!cgContext) { - cgContext = m_contextRef; - if (!cgContext) - return; - else { - m_usePixmap = true; - setNPWindowIfNeeded(); - } - } else - m_usePixmap = false; - - bool oldUsePixmap = m_usePixmap; - if (m_isTransparent && !m_usePixmap) { - if (m_pixmap.isNull()) - m_pixmap = QPixmap(frameRect().size()); - m_usePixmap = true; - setNPWindowIfNeeded(); - cgContext = qt_mac_cg_context(&m_pixmap); - } - - CGContextSaveGState(cgContext); - if (platformPluginWidget()) { - IntPoint offset = frameRect().location(); - CGContextTranslateCTM(cgContext, offset.x(), offset.y()); - } + CGContextSaveGState(m_contextRef); IntRect targetRect(frameRect()); targetRect.intersects(rect); @@ -472,40 +348,40 @@ void PluginView::paint(GraphicsContext* context, const IntRect& rect) r.origin.y = targetRect.y() - frameRect().y(); r.size.width = targetRect.width(); r.size.height = targetRect.height(); - CGContextClipToRect(cgContext, r); + CGContextClipToRect(m_contextRef, r); - if (!platformPluginWidget() || m_isTransparent) { // clean the pixmap in transparent mode -#if PLATFORM(QT) - QPainter painter(&m_pixmap); - painter.setCompositionMode(QPainter::CompositionMode_Clear); - painter.fillRect(QRectF(r.origin.x, r.origin.y, r.size.width, r.size.height), Qt::transparent); -#endif + if (m_isTransparent) { + // Clean the pixmap in transparent mode. + CGContextClearRect(m_contextRef, CGRectMake(r.origin.x, r.origin.y, r.size.width, r.size.height)); } NPCocoaEvent cocoaEvent; initializeNPCocoaEvent(&cocoaEvent); cocoaEvent.type = NPCocoaEventDrawRect; - cocoaEvent.data.draw.x = m_usePixmap ? 0 : r.origin.x; - cocoaEvent.data.draw.y = m_usePixmap ? 0 : r.origin.y; - cocoaEvent.data.draw.width = m_usePixmap ? m_pixmap.width() : r.size.width; - cocoaEvent.data.draw.height = m_usePixmap ? m_pixmap.height() : r.size.height; - cocoaEvent.data.draw.context = cgContext; + cocoaEvent.data.draw.x = 0; + cocoaEvent.data.draw.y = 0; + cocoaEvent.data.draw.width = CGBitmapContextGetWidth(m_contextRef); + cocoaEvent.data.draw.height = CGBitmapContextGetHeight(m_contextRef); + cocoaEvent.data.draw.context = m_contextRef; if(!dispatchNPCocoaEvent(cocoaEvent)) LOG(Events, "PluginView::paint(): Paint event type %d not accepted", cocoaEvent.type); - if (!platformPluginWidget() || m_isTransparent) { #if PLATFORM(QT) - QPainter* painter = context->platformContext(); - painter->drawPixmap(targetRect.x(), targetRect.y(), m_pixmap, - targetRect.x() - frameRect().x(), targetRect.y() - frameRect().y(), targetRect.width(), targetRect.height()); + // Paint the intermediate bitmap into our graphics context. + ASSERT(CGBitmapContextGetBitmapInfo(m_contextRef) & (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); + ASSERT(CGBitmapContextGetBitsPerPixel(m_contextRef) == 32); + const uint8_t* data = reinterpret_cast<const uint8_t*>(CGBitmapContextGetData(m_contextRef)); + size_t width = CGBitmapContextGetWidth(m_contextRef); + size_t height = CGBitmapContextGetHeight(m_contextRef); + const QImage imageFromBitmap(data, width, height, QImage::Format_ARGB32_Premultiplied); + + QPainter* painter = context->platformContext(); + painter->drawImage(targetRect.x(), targetRect.y(), imageFromBitmap, + targetRect.x() - frameRect().x(), targetRect.y() - frameRect().y(), targetRect.width(), targetRect.height()); #endif - } - CGContextRestoreGState(cgContext); - if (oldUsePixmap != m_usePixmap) { - m_usePixmap = oldUsePixmap; - m_pixmap = QPixmap(); - } + + CGContextRestoreGState(m_contextRef); } bool PluginView::popUpContextMenu(NPMenu *menu) @@ -524,12 +400,6 @@ bool PluginView::popUpContextMenu(NPMenu *menu) void PluginView::invalidateRect(const IntRect& rect) { - if (platformPluginWidget() && m_isTransparent) -#if PLATFORM(QT) - static_cast<QWidget*>(platformPluginWidget())->update(convertToContainingWindow(rect)); -#else - platformPluginWidget()->RefreshRect(convertToContainingWindow(rect)); -#endif invalidateWindowlessPluginRect(rect); } |