⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 40366 in webkit


Ignore:
Timestamp:
Jan 29, 2009, 11:21:07 AM (18 years ago)
Author:
Adam Roben
Message:

Fix Bug 23623: Windowed Flash instances aren't captured when a WebView receives a WM_PRINTCLIENT message

WebCore:

Fix Bug 23623: Windowed Flash instances aren't captured when a WebView
receives a WM_PRINTCLIENT message

<​https://bugs.webkit.org/show_bug.cgi?id=23623>
<rdar://problem/6513921>
<rdar://problem/6536874>

Flash doesn't seem to respond to WM_PRINTCLIENT, so we change
WM_PRINTCLIENT messages into WM_PAINT messages and hook into the
BeginPaint/EndPaint APIs to return the HDC we received from
WM_PRINTCLIENT. This causes the plugin to paint into the
WM_PRINTCLIENT HDC via its normal WM_PAINT handler. This technique
came from <​http://www.fengyuan.com/article/wmprint.html>.

No test possible.

Reviewed by Darin Adler.

  • platform/graphics/GraphicsContext.h: Added [set]ShouldIncludeChildWindows on Windows.
  • platform/graphics/cg/GraphicsContextPlatformPrivateCG.h: Added m_shouldIncludeChildWindows. (WebCore::GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate): Initialize the new member.
  • platform/graphics/win/GraphicsContextCGWin.cpp: (WebCore::GraphicsContext::setShouldIncludeChildWindows): (WebCore::GraphicsContext::shouldIncludeChildWindows): Added simple setter and getter.
  • plugins/PluginView.cpp: (WebCore::PluginView::PluginView): Initialize the new member.
  • plugins/PluginView.h: Added m_wmPrintHDC and various functions required for making WM_PRINTCLIENT work.
  • plugins/win/PluginViewWin.cpp: (WebCore::PluginView::hookedBeginPaint): (WebCore::PluginView::hookedEndPaint): (WebCore::hook): (WebCore::setUpOffscreenPaintingHooks): Added. Code was modified from code available on fengyuan.com.

(WebCore::PluginView::wndProc): Turn WM_PRINTCLIENT messages into
WM_PAINT messages and save off the HDC that we're supposed to paint
into.

(WebCore::PluginView::paintWindowedPluginIntoContext): Added. Gets an
HDC from the GraphicsContext, translates it into client coordinates,
gets the plugin to draw into the HDC by sending a WM_PRINTCLIENT
message, and returns the HDC to the GraphicsContext.

(WebCore::PluginView::paint): If we're trying to paint a windowed
plugin into the GraphicsContext, call paintWindowedPluginIntoContext.

(WebCore::PluginView::init): Call setUpOffscreenPaintingHooks to make
our WM_PRINTCLIENT trick work.

WebKit/win:

Fix Bug 23623: Windowed Flash instances aren't captured when a WebView
receives a WM_PRINTCLIENT message

<​https://bugs.webkit.org/show_bug.cgi?id=23623>
<rdar://problem/6513921>
<rdar://problem/6536874>

Reviewed by Darin Adler.

  • WebFrame.cpp: (WebFrame::paintDocumentRectToContext): (WebFrame::spoolPages): Call GraphicsContext::setShouldIncludeChildWindows so that child windows will be painted into the GraphicsContext rather than painted directly to the screen.
  • WebView.cpp: (WebView::updateBackingStore): Added a windowsToPaint parameter, which we pass along to paintIntoBackingStore.

(WebView::paint): Tell updateBackingStore to paint child windows if
we're not painting to the screen.

(WebView::paintIntoBackingStore): Added a windowsToPaint paramter,
which we use to tell our GraphicsContext whether or not to include
child windows.

  • WebView.h: Added windowsToPaint parameters to paintIntoBackingStore and updateBackingStore (which I also made private).
Location:
trunk
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r40364 r40366  
     12009-01-29  Adam Roben  <aroben@apple.com>
     2
     3        Fix Bug 23623: Windowed Flash instances aren't captured when a WebView
     4        receives a WM_PRINTCLIENT message
     5
     6        <https://bugs.webkit.org/show_bug.cgi?id=23623>
     7        <rdar://problem/6513921>
     8        <rdar://problem/6536874>
     9
     10        Flash doesn't seem to respond to WM_PRINTCLIENT, so we change
     11        WM_PRINTCLIENT messages into WM_PAINT messages and hook into the
     12        BeginPaint/EndPaint APIs to return the HDC we received from
     13        WM_PRINTCLIENT. This causes the plugin to paint into the
     14        WM_PRINTCLIENT HDC via its normal WM_PAINT handler. This technique
     15        came from <http://www.fengyuan.com/article/wmprint.html>.
     16
     17        No test possible.
     18
     19        Reviewed by Darin Adler.
     20
     21        * platform/graphics/GraphicsContext.h: Added
     22        [set]ShouldIncludeChildWindows on Windows.
     23
     24        * platform/graphics/cg/GraphicsContextPlatformPrivateCG.h: Added
     25        m_shouldIncludeChildWindows.
     26        (WebCore::GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate):
     27        Initialize the new member.
     28
     29        * platform/graphics/win/GraphicsContextCGWin.cpp:
     30        (WebCore::GraphicsContext::setShouldIncludeChildWindows):
     31        (WebCore::GraphicsContext::shouldIncludeChildWindows):
     32        Added simple setter and getter.
     33
     34        * plugins/PluginView.cpp:
     35        (WebCore::PluginView::PluginView): Initialize the new member.
     36
     37        * plugins/PluginView.h: Added m_wmPrintHDC and various functions
     38        required for making WM_PRINTCLIENT work.
     39
     40        * plugins/win/PluginViewWin.cpp:
     41        (WebCore::PluginView::hookedBeginPaint):
     42        (WebCore::PluginView::hookedEndPaint):
     43        (WebCore::hook):
     44        (WebCore::setUpOffscreenPaintingHooks):
     45        Added. Code was modified from code available on fengyuan.com.
     46
     47        (WebCore::PluginView::wndProc): Turn WM_PRINTCLIENT messages into
     48        WM_PAINT messages and save off the HDC that we're supposed to paint
     49        into.
     50
     51        (WebCore::PluginView::paintWindowedPluginIntoContext): Added. Gets an
     52        HDC from the GraphicsContext, translates it into client coordinates,
     53        gets the plugin to draw into the HDC by sending a WM_PRINTCLIENT
     54        message, and returns the HDC to the GraphicsContext.
     55
     56        (WebCore::PluginView::paint): If we're trying to paint a windowed
     57        plugin into the GraphicsContext, call paintWindowedPluginIntoContext.
     58
     59        (WebCore::PluginView::init): Call setUpOffscreenPaintingHooks to make
     60        our WM_PRINTCLIENT trick work.
     61
    1622009-01-29  David Hyatt  <hyatt@apple.com>
    263
  • trunk/WebCore/platform/graphics/GraphicsContext.h

    r40292 r40366  
    273273        void releaseWindowsContext(HDC, const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true);    // The passed in HDC should be the one handed back by getWindowsContext.
    274274
     275        // When set to true, child windows should be rendered into this context
     276        // rather than allowing them just to render to the screen. Defaults to
     277        // false.
     278        // FIXME: This is a layering violation. GraphicsContext shouldn't know
     279        // what a "window" is. It would be much more appropriate for this flag
     280        // to be passed as a parameter alongside the GraphicsContext, but doing
     281        // that would require lots of changes in cross-platform code that we
     282        // aren't sure we want to make.
     283        void setShouldIncludeChildWindows(bool);
     284        bool shouldIncludeChildWindows() const;
     285
    275286        class WindowsBitmap : public Noncopyable {
    276287        public:
  • trunk/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h

    r39635 r40366  
    3535        , m_hdc(0)
    3636        , m_transparencyCount(0)
     37        , m_shouldIncludeChildWindows(false)
    3738#endif
    3839        , m_userToDeviceTransformKnownToBeIdentity(false)
    … …  
    7576    HDC m_hdc;
    7677    unsigned m_transparencyCount;
     78    bool m_shouldIncludeChildWindows;
    7779#endif
    7880
  • trunk/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp

    r39635 r40366  
    174174}
    175175
     176void GraphicsContext::setShouldIncludeChildWindows(bool include)
     177{
     178    m_data->m_shouldIncludeChildWindows = include;
     179}
     180
     181bool GraphicsContext::shouldIncludeChildWindows() const
     182{
     183    return m_data->m_shouldIncludeChildWindows;
     184}
     185
    176186GraphicsContext::WindowsBitmap::WindowsBitmap(HDC hdc, IntSize size)
    177187    : m_hdc(0)
  • trunk/WebCore/plugins/PluginView.cpp

    r40196 r40366  
    566566    , m_lastMessage(0)
    567567    , m_isCallingPluginWndProc(false)
     568    , m_wmPrintHDC(0)
    568569#endif
    569570#if (PLATFORM(QT) && PLATFORM(WIN_OS)) || defined(XP_MACOSX)
  • trunk/WebCore/plugins/PluginView.h

    r39616 r40366  
    208208
    209209        void invalidateWindowlessPluginRect(const IntRect&);
    210        
     210
     211#if PLATFORM(WIN_OS) && !PLATFORM(WX) && ENABLE(NETSCAPE_PLUGIN_API)
     212        void paintWindowedPluginIntoContext(GraphicsContext*, const IntRect&) const;
     213        static HDC WINAPI hookedBeginPaint(HWND, PAINTSTRUCT*);
     214        static BOOL WINAPI hookedEndPaint(HWND, const PAINTSTRUCT*);
     215#endif
     216
    211217        Frame* m_parentFrame;
    212218        RefPtr<PluginPackage> m_plugin;
    … …  
    271277        unsigned m_lastMessage;
    272278        bool m_isCallingPluginWndProc;
     279        HDC m_wmPrintHDC;
    273280#endif
    274281
  • trunk/WebCore/plugins/win/PluginViewWin.cpp

    r39238 r40366  
    100100static const char* MozillaUserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0";
    101101
     102// The code used to hook BeginPaint/EndPaint originally came from
     103// <http://www.fengyuan.com/article/wmprint.html>.
     104// Copyright (C) 2000 by Feng Yuan (www.fengyuan.com).
     105
     106static unsigned beginPaintSysCall;
     107static BYTE* beginPaint;
     108
     109static unsigned endPaintSysCall;
     110static BYTE* endPaint;
     111
     112HDC WINAPI PluginView::hookedBeginPaint(HWND hWnd, PAINTSTRUCT* lpPaint)
     113{
     114    PluginView* pluginView = reinterpret_cast<PluginView*>(GetProp(hWnd, kWebPluginViewProperty));
     115    if (pluginView && pluginView->m_wmPrintHDC) {
     116        // We're secretly handling WM_PRINTCLIENT, so set up the PAINTSTRUCT so
     117        // that the plugin will paint into the HDC we provide.
     118        memset(lpPaint, 0, sizeof(PAINTSTRUCT));
     119        lpPaint->hdc = pluginView->m_wmPrintHDC;
     120        GetClientRect(hWnd, &lpPaint->rcPaint);
     121        return pluginView->m_wmPrintHDC;
     122    }
     123
     124    // Call through to the original BeginPaint.
     125    __asm   mov     eax, beginPaintSysCall
     126    __asm   push    lpPaint
     127    __asm   push    hWnd
     128    __asm   call    beginPaint
     129}
     130
     131BOOL WINAPI PluginView::hookedEndPaint(HWND hWnd, const PAINTSTRUCT* lpPaint)
     132{
     133    PluginView* pluginView = reinterpret_cast<PluginView*>(GetProp(hWnd, kWebPluginViewProperty));
     134    if (pluginView && pluginView->m_wmPrintHDC) {
     135        // We're secretly handling WM_PRINTCLIENT, so we don't have to do any
     136        // cleanup.
     137        return TRUE;
     138    }
     139
     140    // Call through to the original EndPaint.
     141    __asm   mov     eax, endPaintSysCall
     142    __asm   push    lpPaint
     143    __asm   push    hWnd
     144    __asm   call    endPaint
     145}
     146
     147static void hook(const char* module, const char* proc, unsigned& sysCallID, BYTE*& pProc, const void* pNewProc)
     148{
     149    // See <http://www.fengyuan.com/article/wmprint.html> for an explanation of
     150    // how this function works.
     151
     152    HINSTANCE hMod = GetModuleHandleA(module);
     153
     154    pProc = reinterpret_cast<BYTE*>(GetProcAddress(hMod, proc));
     155
     156    if (pProc[0] != 0xB8)
     157        return;
     158
     159    // FIXME: Should we be reading the bytes one-by-one instead of doing an
     160    // unaligned read?
     161    sysCallID = *reinterpret_cast<unsigned*>(pProc + 1);
     162
     163    DWORD flOldProtect;
     164    if (!VirtualProtect(pProc, 5, PAGE_EXECUTE_READWRITE, &flOldProtect))
     165        return;
     166
     167    pProc[0] = 0xE9;
     168    *reinterpret_cast<unsigned*>(pProc + 1) = reinterpret_cast<intptr_t>(pNewProc) - reinterpret_cast<intptr_t>(pProc + 5);
     169
     170    pProc += 5;
     171}
     172
     173static void setUpOffscreenPaintingHooks(HDC (WINAPI*hookedBeginPaint)(HWND, PAINTSTRUCT*), BOOL (WINAPI*hookedEndPaint)(HWND, const PAINTSTRUCT*))
     174{
     175    static bool haveHooked = false;
     176    if (haveHooked)
     177        return;
     178    haveHooked = true;
     179
     180    // Most (all?) windowed plugins don't seem to respond to WM_PRINTCLIENT, so
     181    // we hook into BeginPaint/EndPaint to allow their normal WM_PAINT handling
     182    // to draw into a given HDC. Note that this hooking affects the entire
     183    // process.
     184    hook("user32.dll", "BeginPaint", beginPaintSysCall, beginPaint, hookedBeginPaint);
     185    hook("user32.dll", "EndPaint", endPaintSysCall, endPaint, hookedEndPaint);
     186}
     187
    102188static bool registerPluginView()
    103189{
    … …  
    202288    }
    203289
     290    if (message == WM_PRINTCLIENT) {
     291        // Most (all?) windowed plugins don't respond to WM_PRINTCLIENT, so we
     292        // change the message to WM_PAINT and rely on our hooked versions of
     293        // BeginPaint/EndPaint to make the plugin draw into the given HDC.
     294        message = WM_PAINT;
     295        m_wmPrintHDC = reinterpret_cast<HDC>(wParam);
     296    }
     297
    204298    // Call the plug-in's window proc.
    205299    LRESULT result = ::CallWindowProc(m_pluginWndProc, hWnd, message, wParam, lParam);
     300
     301    m_wmPrintHDC = 0;
    206302
    207303    m_isCallingPluginWndProc = false;
    … …  
    306402}
    307403
     404void PluginView::paintWindowedPluginIntoContext(GraphicsContext* context, const IntRect& rect) const
     405{
     406    ASSERT(m_isWindowed);
     407    ASSERT(context->shouldIncludeChildWindows());
     408
     409    ASSERT(parent()->isFrameView());
     410    IntPoint locationInWindow = static_cast<FrameView*>(parent())->contentsToWindow(frameRect().location());
     411
     412    HDC hdc = context->getWindowsContext(frameRect(), false);
     413
     414    XFORM originalTransform;
     415    GetWorldTransform(hdc, &originalTransform);
     416
     417    // The plugin expects the DC to be in client coordinates, so we translate
     418    // the DC to make that so.
     419    XFORM transform = originalTransform;
     420    transform.eDx = locationInWindow.x();
     421    transform.eDy = locationInWindow.y();
     422
     423    SetWorldTransform(hdc, &transform);
     424
     425    SendMessage(platformPluginWidget(), WM_PRINTCLIENT, reinterpret_cast<WPARAM>(hdc), PRF_CLIENT | PRF_CHILDREN | PRF_OWNED);
     426
     427    SetWorldTransform(hdc, &originalTransform);
     428
     429    context->releaseWindowsContext(hdc, frameRect(), false);
     430}
     431
    308432void PluginView::paint(GraphicsContext* context, const IntRect& rect)
    309433{
    … …  
    314438    }
    315439
    316     if (m_isWindowed || context->paintingDisabled())
    317         return;
     440    if (context->paintingDisabled())
     441        return;
     442
     443    if (m_isWindowed) {
     444        if (context->shouldIncludeChildWindows())
     445            paintWindowedPluginIntoContext(context, rect);
     446        return;
     447    }
    318448
    319449    ASSERT(parent()->isFrameView());
    … …  
    801931    if (m_isWindowed) {
    802932        registerPluginView();
     933        setUpOffscreenPaintingHooks(hookedBeginPaint, hookedEndPaint);
    803934
    804935        DWORD flags = WS_CHILD;
  • trunk/WebKit/win/ChangeLog

    r40365 r40366  
     12009-01-29  Adam Roben  <aroben@apple.com>
     2
     3        Fix Bug 23623: Windowed Flash instances aren't captured when a WebView
     4        receives a WM_PRINTCLIENT message
     5
     6        <https://bugs.webkit.org/show_bug.cgi?id=23623>
     7        <rdar://problem/6513921>
     8        <rdar://problem/6536874>
     9
     10        Reviewed by Darin Adler.
     11
     12        * WebFrame.cpp:
     13        (WebFrame::paintDocumentRectToContext):
     14        (WebFrame::spoolPages):
     15        Call GraphicsContext::setShouldIncludeChildWindows so that child
     16        windows will be painted into the GraphicsContext rather than painted
     17        directly to the screen.
     18
     19        * WebView.cpp:
     20        (WebView::updateBackingStore): Added a windowsToPaint parameter, which
     21        we pass along to paintIntoBackingStore.
     22
     23        (WebView::paint): Tell updateBackingStore to paint child windows if
     24        we're not painting to the screen.
     25
     26        (WebView::paintIntoBackingStore): Added a windowsToPaint paramter,
     27        which we use to tell our GraphicsContext whether or not to include
     28        child windows.
     29
     30        * WebView.h: Added windowsToPaint parameters to paintIntoBackingStore
     31        and updateBackingStore (which I also made private).
     32
    1332009-01-29  Adam Roben  <aroben@apple.com>
    234
  • trunk/WebKit/win/WebFrame.cpp

    r40289 r40366  
    314314    HDC dc = (HDC)(ULONG64)deviceContext;
    315315    GraphicsContext gc(dc);
     316    gc.setShouldIncludeChildWindows(true);
    316317    gc.save();
    317318    LONG width = rect.right - rect.left;
    … …  
    18131814    headerAndFooterHeights(&headerHeight, &footerHeight);
    18141815    GraphicsContext spoolCtx(pctx);
     1816    spoolCtx.setShouldIncludeChildWindows(true);
    18151817
    18161818    for (UINT ii = startPage; ii < endPage; ii++) {
  • trunk/WebKit/win/WebView.cpp

    r40353 r40366  
    820820}
    821821
    822 void WebView::updateBackingStore(FrameView* frameView, HDC dc, bool backingStoreCompletelyDirty)
     822void WebView::updateBackingStore(FrameView* frameView, HDC dc, bool backingStoreCompletelyDirty, WindowsToPaint windowsToPaint)
    823823{
    824824    LOCAL_GDI_COUNTER(0, __FUNCTION__);
    … …  
    850850
    851851        for (unsigned i = 0; i < paintRects.size(); ++i)
    852             paintIntoBackingStore(frameView, bitmapDC, paintRects[i]);
     852            paintIntoBackingStore(frameView, bitmapDC, paintRects[i], windowsToPaint);
    853853
    854854        if (m_uiDelegatePrivate) {
    … …  
    885885    int regionType = NULLREGION;
    886886    PAINTSTRUCT ps;
     887    WindowsToPaint windowsToPaint;
    887888    if (!dc) {
    888889        region.set(CreateRectRgn(0,0,0,0));
    … …  
    890891        hdc = BeginPaint(m_viewWindow, &ps);
    891892        rcPaint = ps.rcPaint;
     893        // We're painting to the screen, and our child windows can handle
     894        // painting themselves to the screen.
     895        windowsToPaint = PaintWebViewOnly;
    892896    } else {
    893897        hdc = dc;
    … …  
    895899        if (options & PRF_ERASEBKGND)
    896900            ::FillRect(hdc, &rcPaint, (HBRUSH)GetStockObject(WHITE_BRUSH));
     901        // Since we aren't painting to the screen, we want to paint all our
     902        // children into the HDC.
     903        windowsToPaint = PaintWebViewAndChildren;
    897904    }
    898905
    … …  
    902909
    903910    // Update our backing store if needed.
    904     updateBackingStore(frameView, bitmapDC, backingStoreCompletelyDirty);
     911    updateBackingStore(frameView, bitmapDC, backingStoreCompletelyDirty, windowsToPaint);
    905912
    906913    // Now we blit the updated backing store
    … …  
    943950}
    944951
    945 void WebView::paintIntoBackingStore(FrameView* frameView, HDC bitmapDC, const IntRect& dirtyRect)
     952void WebView::paintIntoBackingStore(FrameView* frameView, HDC bitmapDC, const IntRect& dirtyRect, WindowsToPaint windowsToPaint)
    946953{
    947954    LOCAL_GDI_COUNTER(0, __FUNCTION__);
    … …  
    960967
    961968    GraphicsContext gc(bitmapDC, m_transparent);
     969    gc.setShouldIncludeChildWindows(windowsToPaint == PaintWebViewAndChildren);
    962970    gc.save();
    963971    if (m_transparent)
  • trunk/WebKit/win/WebView.h

    r39757 r40366  
    744744    bool inResizer(LPARAM lParam);
    745745    void paint(HDC, LPARAM);
    746     void paintIntoBackingStore(WebCore::FrameView*, HDC bitmapDC, const WebCore::IntRect& dirtyRect);
    747746    void paintIntoWindow(HDC bitmapDC, HDC windowDC, const WebCore::IntRect& dirtyRect);
    748747    bool ensureBackingStore();
    … …  
    750749    void addToDirtyRegion(HRGN);
    751750    void scrollBackingStore(WebCore::FrameView*, int dx, int dy, const WebCore::IntRect& scrollViewRect, const WebCore::IntRect& clipRect);
    752     void updateBackingStore(WebCore::FrameView*, HDC = 0, bool backingStoreCompletelyDirty = false);
    753751    void deleteBackingStore();
    754752    void repaint(const WebCore::IntRect&, bool contentChanged, bool immediate = false, bool repaintContentOnly = false);
    … …  
    826824    HRESULT resetZoom(bool isTextOnly);
    827825    bool active();
     826
     827    enum WindowsToPaint { PaintWebViewOnly, PaintWebViewAndChildren };
     828    void paintIntoBackingStore(WebCore::FrameView*, HDC bitmapDC, const WebCore::IntRect& dirtyRect, WindowsToPaint);
     829    void updateBackingStore(WebCore::FrameView*, HDC = 0, bool backingStoreCompletelyDirty = false, WindowsToPaint = PaintWebViewOnly);
    828830
    829831protected:
Note: See TracChangeset for help on using the changeset viewer.