<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" /><style type="text/css"><!--
#msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; }
#msg ul, pre { overflow: auto; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<title>[20668] trunk/WebKit</title>
</head>
<body>

<div id="msg">
<dl>
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/20668">20668</a></dd>
<dt>Author</dt> <dd>darin</dd>
<dt>Date</dt> <dd>2007-04-02 14:15:34 -0700 (Mon, 02 Apr 2007)</dd>
</dl>

<h3>Log Message</h3>
<pre>        Reviewed by Geoff.

        - fix http://bugs.webkit.org/show_bug.cgi?id=13026
          &lt;rdar://problem/5061026&gt; incomplete render of menu
          (assertion failing in -[WebBaseNetscapePluginView saveAndSetNewPortStateForUpdate:])

        - fix http://bugs.webkit.org/show_bug.cgi?id=13120
          &lt;rdar://problem/5080339&gt; Plug-ins that draw through the QuickDraw interface may crash
          by hanging onto old GWorlds.

        - set clip path for CoreGraphics plug-ins in the same way we do for QuickDraw plug-ins
          this is a better fix for &lt;rdar://problem/4939511&gt; WebKit should set the the CG clip
          path for plug-ins that draw using Core Graphics

        Incorporates changes from a patch by Mark Ambachtsheer.

        Here are the changes:

            1) Don't try to use the offscreen code path if GGBitmapContextGetData returns 0.
            2) Handle kCGBitmapByteOrderDefault when computing the QD pixel format, even though
               we don't have any evidence that this happens in practice.
            3) Keep the GWorld around until we create a new one or the plug-in is destroyed.
            4) Use the GWorld pointer itself as a flag to indicate whether we are using an
               offscreen GWorld.
            5) Set up clipping for CoreGraphics in the same way we do for QuickDraw; remove an
               earlier attempt that handled CoreGraphics differently.

        * Plugins/WebBaseNetscapePluginView.h: Added a field named offscreenGWorld to hold
        the GWorld until it's needed.
        * Plugins/WebBaseNetscapePluginView.mm:
        (getQDPixelFormatForBitmapContext): Replaced QDPixelFormatFromCGBitmapInfo. Used the
        &quot;get&quot; prefix so we don't intrude on the QD namespace. Added code to handle the
        kCGBitmapByteOrderDefault case, although I'm not sure it will really come up in
        practice -- it wasn't really coming up in the buggy case.
        (getNPRect): Added helper functions. Used to make the code below clearer.
        (-[WebBaseNetscapePluginView saveAndSetNewPortStateForUpdate:]): Use getNPRect to
        streamline code. Use GetGWorld to save the port since we use SetGWorld to restore
        it later. Store the GWorld we create in the offscreenGWorld field and dispose the
        existing one. Don't treat the CGBitmapContext as an offscreen bitmap if it
        has a data pointer of 0. Set up the clip based on the result of
        -[NSView getRectsBeingDrawn:count] when setting up the port for CoreGraphics
        (after saving the port state).
        (-[WebBaseNetscapePluginView restorePortState:]): Remove now-unneeded code to
        destroy the offscreen GWorld, and simplified the code that restores the port so we
        don't need a separate case for offscreen.
        (-[WebBaseNetscapePluginView fini]): Renamed from freeAttributeKeysAndValues, since
        this method now does more than just the attributes. This is the shared method that
        does things needed in both dealloc and finalize. Added a call to DisposeGWorld here.
        (-[WebBaseNetscapePluginView dealloc]): Updated for name change.
        (-[WebBaseNetscapePluginView finalize]): Ditto.
        (-[WebBaseNetscapePluginView drawRect:]): Removed code to set clip. This is done in
        the saveAndSetNewPortStateForUpdate: method instead.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkWebKitChangeLog">trunk/WebKit/ChangeLog</a></li>
<li><a href="#trunkWebKitPluginsWebBaseNetscapePluginViewh">trunk/WebKit/Plugins/WebBaseNetscapePluginView.h</a></li>
<li><a href="#trunkWebKitPluginsWebBaseNetscapePluginViewmm">trunk/WebKit/Plugins/WebBaseNetscapePluginView.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkWebKitChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/WebKit/ChangeLog (20667 => 20668)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebKit/ChangeLog        2007-04-02 20:38:53 UTC (rev 20667)
+++ trunk/WebKit/ChangeLog        2007-04-02 21:15:34 UTC (rev 20668)
</span><span class="lines">@@ -1,3 +1,58 @@
</span><ins>+2007-04-02  Darin Adler  &lt;darin@apple.com&gt;
+
+        Reviewed by Geoff.
+
+        - fix http://bugs.webkit.org/show_bug.cgi?id=13026
+          &lt;rdar://problem/5061026&gt; incomplete render of menu
+          (assertion failing in -[WebBaseNetscapePluginView saveAndSetNewPortStateForUpdate:])
+
+        - fix http://bugs.webkit.org/show_bug.cgi?id=13120
+          &lt;rdar://problem/5080339&gt; Plug-ins that draw through the QuickDraw interface may crash
+          by hanging onto old GWorlds.
+
+        - set clip path for CoreGraphics plug-ins in the same way we do for QuickDraw plug-ins
+          this is a better fix for &lt;rdar://problem/4939511&gt; WebKit should set the the CG clip
+          path for plug-ins that draw using Core Graphics
+
+        Incorporates changes from a patch by Mark Ambachtsheer.
+
+        Here are the changes:
+
+            1) Don't try to use the offscreen code path if GGBitmapContextGetData returns 0.
+            2) Handle kCGBitmapByteOrderDefault when computing the QD pixel format, even though
+               we don't have any evidence that this happens in practice.
+            3) Keep the GWorld around until we create a new one or the plug-in is destroyed.
+            4) Use the GWorld pointer itself as a flag to indicate whether we are using an
+               offscreen GWorld.
+            5) Set up clipping for CoreGraphics in the same way we do for QuickDraw; remove an
+               earlier attempt that handled CoreGraphics differently.
+
+        * Plugins/WebBaseNetscapePluginView.h: Added a field named offscreenGWorld to hold
+        the GWorld until it's needed.
+        * Plugins/WebBaseNetscapePluginView.mm:
+        (getQDPixelFormatForBitmapContext): Replaced QDPixelFormatFromCGBitmapInfo. Used the
+        &quot;get&quot; prefix so we don't intrude on the QD namespace. Added code to handle the
+        kCGBitmapByteOrderDefault case, although I'm not sure it will really come up in
+        practice -- it wasn't really coming up in the buggy case.
+        (getNPRect): Added helper functions. Used to make the code below clearer.
+        (-[WebBaseNetscapePluginView saveAndSetNewPortStateForUpdate:]): Use getNPRect to
+        streamline code. Use GetGWorld to save the port since we use SetGWorld to restore
+        it later. Store the GWorld we create in the offscreenGWorld field and dispose the
+        existing one. Don't treat the CGBitmapContext as an offscreen bitmap if it
+        has a data pointer of 0. Set up the clip based on the result of
+        -[NSView getRectsBeingDrawn:count] when setting up the port for CoreGraphics
+        (after saving the port state).
+        (-[WebBaseNetscapePluginView restorePortState:]): Remove now-unneeded code to
+        destroy the offscreen GWorld, and simplified the code that restores the port so we
+        don't need a separate case for offscreen.
+        (-[WebBaseNetscapePluginView fini]): Renamed from freeAttributeKeysAndValues, since
+        this method now does more than just the attributes. This is the shared method that
+        does things needed in both dealloc and finalize. Added a call to DisposeGWorld here.
+        (-[WebBaseNetscapePluginView dealloc]): Updated for name change.
+        (-[WebBaseNetscapePluginView finalize]): Ditto.
+        (-[WebBaseNetscapePluginView drawRect:]): Removed code to set clip. This is done in
+        the saveAndSetNewPortStateForUpdate: method instead.
+
</ins><span class="cx"> 2007-03-30  Adele Peterson  &lt;adele@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Reviewed by Darin.
</span></span></pre></div>
<a id="trunkWebKitPluginsWebBaseNetscapePluginViewh"></a>
<div class="modfile"><h4>Modified: trunk/WebKit/Plugins/WebBaseNetscapePluginView.h (20667 => 20668)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebKit/Plugins/WebBaseNetscapePluginView.h        2007-04-02 20:38:53 UTC (rev 20667)
+++ trunk/WebKit/Plugins/WebBaseNetscapePluginView.h        2007-04-02 21:15:34 UTC (rev 20668)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
</del><ins>+ * Copyright (C) 2005, 2007 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -79,6 +79,11 @@
</span><span class="cx">     AGLContext aglContext;
</span><span class="cx">     NSWindow *aglWindow;
</span><span class="cx"> 
</span><ins>+#ifndef NP_NO_QUICKDRAW
+    // This is only valid when drawingModel is NPDrawingModelQuickDraw
+    GWorldPtr offscreenGWorld;
+#endif
+
</ins><span class="cx">     BOOL isStarted;
</span><span class="cx">     BOOL inSetWindow;
</span><span class="cx">     BOOL suspendKeyUpEvents;
</span></span></pre></div>
<a id="trunkWebKitPluginsWebBaseNetscapePluginViewmm"></a>
<div class="modfile"><h4>Modified: trunk/WebKit/Plugins/WebBaseNetscapePluginView.mm (20667 => 20668)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebKit/Plugins/WebBaseNetscapePluginView.mm        2007-04-02 20:38:53 UTC (rev 20667)
+++ trunk/WebKit/Plugins/WebBaseNetscapePluginView.mm        2007-04-02 21:15:34 UTC (rev 20668)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2005, 2006 Apple Computer, Inc.  All rights reserved.
</del><ins>+ * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -99,6 +99,7 @@
</span><span class="cx"> 
</span><span class="cx"> typedef struct {
</span><span class="cx">     GrafPtr oldPort;
</span><ins>+    GDHandle oldDevice;
</ins><span class="cx">     Point oldOrigin;
</span><span class="cx">     RgnHandle oldClipRegion;
</span><span class="cx">     RgnHandle oldVisibleRegion;
</span><span class="lines">@@ -237,6 +238,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #ifndef NP_NO_QUICKDRAW
</span><ins>+
</ins><span class="cx"> // The WindowRef created by -[NSWindow windowRef] has a QuickDraw GrafPort that covers 
</span><span class="cx"> // the entire window frame (or structure region to use the Carbon term) rather then just the window content.
</span><span class="cx"> // We can remove this when &lt;rdar://problem/4201099&gt; is fixed.
</span><span class="lines">@@ -261,30 +263,51 @@
</span><span class="cx">     
</span><span class="cx">     SetPort(oldPort);
</span><span class="cx"> }
</span><del>-#endif
</del><span class="cx"> 
</span><del>-#ifndef NP_NO_QUICKDRAW
-static UInt32 QDPixelFormatFromCGBitmapInfo(CGBitmapInfo bitmapInfo)
</del><ins>+static UInt32 getQDPixelFormatForBitmapContext(CGContextRef context)
</ins><span class="cx"> {
</span><del>-    UInt32 cgByteOrder = bitmapInfo &amp; kCGBitmapByteOrderMask;
-    switch (cgByteOrder) {
-    case kCGBitmapByteOrderDefault:
-        return 0;
-    case kCGBitmapByteOrder16Little:
-        return k16LE555PixelFormat;
-    case kCGBitmapByteOrder32Little:
-        return k32BGRAPixelFormat;
-    case kCGBitmapByteOrder16Big:
-        return k16BE555PixelFormat;
-    case kCGBitmapByteOrder32Big:
-        return k32ARGBPixelFormat;
-    default:
-        ASSERT_NOT_REACHED();
-        return 0;
</del><ins>+    UInt32 byteOrder = CGBitmapContextGetBitmapInfo(context) &amp; kCGBitmapByteOrderMask;
+    if (byteOrder == kCGBitmapByteOrderDefault)
+        switch (CGBitmapContextGetBitsPerPixel(context)) {
+            case 16:
+                byteOrder = kCGBitmapByteOrder16Host;
+                break;
+            case 32:
+                byteOrder = kCGBitmapByteOrder32Host;
+                break;
+        }
+    switch (byteOrder) {
+        case kCGBitmapByteOrder16Little:
+            return k16LE555PixelFormat;
+        case kCGBitmapByteOrder32Little:
+            return k32BGRAPixelFormat;
+        case kCGBitmapByteOrder16Big:
+            return k16BE555PixelFormat;
+        case kCGBitmapByteOrder32Big:
+            return k32ARGBPixelFormat;
</ins><span class="cx">     }
</span><ins>+    ASSERT_NOT_REACHED();
+    return 0;
</ins><span class="cx"> }
</span><ins>+
+static inline void getNPRect(const CGRect&amp; cgr, NPRect&amp; npr)
+{
+    npr.top = static_cast&lt;uint16&gt;(cgr.origin.y);
+    npr.left = static_cast&lt;uint16&gt;(cgr.origin.x);
+    npr.bottom = static_cast&lt;uint16&gt;(CGRectGetMaxY(cgr));
+    npr.right = static_cast&lt;uint16&gt;(CGRectGetMaxX(cgr));
+}
+
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+static inline void getNPRect(const NSRect&amp; nr, NPRect&amp; npr)
+{
+    npr.top = static_cast&lt;uint16&gt;(nr.origin.y);
+    npr.left = static_cast&lt;uint16&gt;(nr.origin.x);
+    npr.bottom = static_cast&lt;uint16&gt;(NSMaxY(nr));
+    npr.right = static_cast&lt;uint16&gt;(NSMaxX(nr));
+}
+
</ins><span class="cx"> - (PortState)saveAndSetNewPortStateForUpdate:(BOOL)forUpdate
</span><span class="cx"> {
</span><span class="cx">     ASSERT([self currentWindow] != nil);
</span><span class="lines">@@ -295,7 +318,7 @@
</span><span class="cx">     if (drawingModel == NPDrawingModelQuickDraw)
</span><span class="cx">         [self fixWindowPort];
</span><span class="cx"> #endif
</span><del>-    
</del><ins>+
</ins><span class="cx">     WindowRef windowRef = (WindowRef)[[self currentWindow] windowRef];
</span><span class="cx">     ASSERT(windowRef);
</span><span class="cx">     
</span><span class="lines">@@ -340,6 +363,7 @@
</span><span class="cx">             || [NSApp isHidden]
</span><span class="cx">             || ![self superviewsHaveSuperviews]
</span><span class="cx">             || [self isHiddenOrHasHiddenAncestor]) {
</span><ins>+
</ins><span class="cx">         // The following code tries to give plug-ins the same size they will eventually have.
</span><span class="cx">         // The specifiedWidth and specifiedHeight variables are used to predict the size that
</span><span class="cx">         // WebCore will eventually resize us to.
</span><span class="lines">@@ -348,28 +372,22 @@
</span><span class="cx">         // Since other plug-ins also might have the same sort of trouble, we make sure
</span><span class="cx">         // to always give plug-ins a size other than 0,0.
</span><span class="cx"> 
</span><del>-        if (window.width &lt;= 0) {
</del><ins>+        if (window.width &lt;= 0)
</ins><span class="cx">             window.width = specifiedWidth &gt; 0 ? specifiedWidth : 100;
</span><del>-        }
-        if (window.height &lt;= 0) {
</del><ins>+        if (window.height &lt;= 0)
</ins><span class="cx">             window.height = specifiedHeight &gt; 0 ? specifiedHeight : 100;
</span><del>-        }
</del><span class="cx"> 
</span><span class="cx">         window.clipRect.bottom = window.clipRect.top;
</span><span class="cx">         window.clipRect.left = window.clipRect.right;
</span><span class="cx">     } else {
</span><del>-        window.clipRect.top = (uint16)visibleRectInWindow.origin.y;
-        window.clipRect.left = (uint16)visibleRectInWindow.origin.x;
-        window.clipRect.bottom = (uint16)(visibleRectInWindow.origin.y + visibleRectInWindow.size.height);
-        window.clipRect.right = (uint16)(visibleRectInWindow.origin.x + visibleRectInWindow.size.width);        
</del><ins>+        getNPRect(visibleRectInWindow, window.clipRect);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     // Save the port state, set up the port for entry into the plugin
</span><span class="cx">     PortState portState;
</span><span class="cx">     switch (drawingModel) {
</span><span class="cx"> #ifndef NP_NO_QUICKDRAW
</span><del>-        case NPDrawingModelQuickDraw:
-        {
</del><ins>+        case NPDrawingModelQuickDraw: {
</ins><span class="cx">             // Set up NS_Port.
</span><span class="cx">             Rect portBounds;
</span><span class="cx">             CGrafPtr port = GetWindowPort(windowRef);
</span><span class="lines">@@ -382,7 +400,7 @@
</span><span class="cx">             PortState_QD *qdPortState = (PortState_QD*)malloc(sizeof(PortState_QD));
</span><span class="cx">             portState = (PortState)qdPortState;
</span><span class="cx">             
</span><del>-            GetPort(&amp;qdPortState-&gt;oldPort);    
</del><ins>+            GetGWorld(&amp;qdPortState-&gt;oldPort, &amp;qdPortState-&gt;oldDevice);    
</ins><span class="cx"> 
</span><span class="cx">             qdPortState-&gt;oldOrigin.h = portBounds.left;
</span><span class="cx">             qdPortState-&gt;oldOrigin.v = portBounds.top;
</span><span class="lines">@@ -397,49 +415,48 @@
</span><span class="cx">             qdPortState-&gt;clipRegion = clipRegion;
</span><span class="cx"> 
</span><span class="cx">             CGContextRef currentContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
</span><del>-            // If the current context is an offscreen bitmap, then we create a GWorld for it
-            bool offScreenContext = currentContext &amp;&amp; WKCGContextIsBitmapContext(currentContext);
-            if (offScreenContext) {
-                CGBitmapInfo contextBitmapInfo = CGBitmapContextGetBitmapInfo(currentContext);
-                GWorldPtr pOffScreenGWorld;
-                Rect offscreenBounds;
-                int rowBytes = CGBitmapContextGetBytesPerRow(currentContext);
-                offscreenBounds.top = 0;
-                offscreenBounds.left = 0;
-                offscreenBounds.right = CGBitmapContextGetWidth(currentContext);
-                offscreenBounds.bottom = CGBitmapContextGetHeight(currentContext);
-                UInt32 pixelFormat = QDPixelFormatFromCGBitmapInfo(contextBitmapInfo);
-                if (pixelFormat == 0) {
-                    // Not a valid pixel format - don't render at all.
</del><ins>+            if (currentContext &amp;&amp; WKCGContextIsBitmapContext(currentContext)) {
+                // We use WKCGContextIsBitmapContext here, because if we just called CGBitmapContextGetData
+                // on any context, we'd log to the console every time. But even if WKCGContextIsBitmapContext
+                // returns true, it still might not be a context we need to create a GWorld for; for example
+                // transparency layers will return true, but return 0 for CGBitmapContextGetData.
+                void* offscreenData = CGBitmapContextGetData(currentContext);
+                if (offscreenData) {
+                    // If the current context is an offscreen bitmap, then create a GWorld for it.
+                    Rect offscreenBounds;
</ins><span class="cx">                     offscreenBounds.top = 0;
</span><span class="cx">                     offscreenBounds.left = 0;
</span><del>-                    offscreenBounds.right = 0;
-                    offscreenBounds.bottom = 0;
-                    rowBytes = 0;
-                    pixelFormat = k32BGRAPixelFormat;
-                }
-                void* bits = CGBitmapContextGetData(currentContext);
-                QDErr err = NewGWorldFromPtr(&amp;pOffScreenGWorld, pixelFormat, &amp;offscreenBounds, 0, 0, 0, static_cast&lt;char*&gt;(bits), rowBytes);
-                ASSERT(pOffScreenGWorld &amp;&amp; !err);
-                if (!err) {
-                    SetGWorld(pOffScreenGWorld, NULL);
-                    nPort.qdPort.port = pOffScreenGWorld;
-                    NSRect boundsInWindow = [self bounds];
-                    nPort.qdPort.portx = ((int32)-boundsInWindow.origin.x);
-                    nPort.qdPort.porty = ((int32)-boundsInWindow.origin.y);
-                    window.x = 0;
-                    window.y = 0;
-                    window.window = &amp;nPort;
</del><ins>+                    offscreenBounds.right = CGBitmapContextGetWidth(currentContext);
+                    offscreenBounds.bottom = CGBitmapContextGetHeight(currentContext);
+                    GWorldPtr newOffscreenGWorld;
+                    QDErr err = NewGWorldFromPtr(&amp;newOffscreenGWorld,
+                        getQDPixelFormatForBitmapContext(currentContext), &amp;offscreenBounds, 0, 0, 0,
+                        static_cast&lt;char*&gt;(offscreenData), CGBitmapContextGetBytesPerRow(currentContext));
+                    ASSERT(newOffscreenGWorld &amp;&amp; !err);
+                    if (!err) {
+                        if (offscreenGWorld)
+                            DisposeGWorld(offscreenGWorld);
+                        offscreenGWorld = newOffscreenGWorld;
</ins><span class="cx"> 
</span><del>-                    // Get the clip bounds for the existing context and use that for the plug-in's window.clipRect.
-                    // The plug-in will intersect this clip rect with the port's dirty region clip constructed below. 
-                    CGRect contextClip = CGContextGetClipBoundingBox(currentContext);
-                    window.clipRect.top = (uint16)contextClip.origin.y;
-                    window.clipRect.left = (uint16)contextClip.origin.x;
-                    window.clipRect.right = (uint16)window.clipRect.left + (uint16)contextClip.size.width;
-                    window.clipRect.bottom = (uint16)window.clipRect.top + (uint16)contextClip.size.height;
</del><ins>+                        SetGWorld(offscreenGWorld, NULL);
+
+                        port = offscreenGWorld;
+
+                        nPort.qdPort.port = port;
+                        boundsInWindow = [self bounds];
+                        nPort.qdPort.portx = (int32)-boundsInWindow.origin.x;
+                        nPort.qdPort.porty = (int32)-boundsInWindow.origin.y;
+                        window.x = 0;
+                        window.y = 0;
+                        window.window = &amp;nPort;
+
+                        // Use the clip bounds from the context instead of the bounds we created
+                        // from the window above.
+                        getNPRect(CGContextGetClipBoundingBox(currentContext), window.clipRect);
+                    }
</ins><span class="cx">                 }
</span><span class="cx">             }
</span><ins>+
</ins><span class="cx">             MacSetRectRgn(clipRegion,
</span><span class="cx">                 window.clipRect.left + nPort.qdPort.portx, window.clipRect.top + nPort.qdPort.porty,
</span><span class="cx">                 window.clipRect.right + nPort.qdPort.portx, window.clipRect.bottom + nPort.qdPort.porty);
</span><span class="lines">@@ -474,13 +491,12 @@
</span><span class="cx">                 // Intersect the dirty region with the clip region, so that we only draw over dirty parts
</span><span class="cx">                 SectRgn(clipRegion, viewClipRegion, clipRegion);
</span><span class="cx">                 DisposeRgn(viewClipRegion);
</span><del>-                if (offScreenContext) {
</del><ins>+                if (port == offscreenGWorld) {
</ins><span class="cx">                     GetRegionBounds(clipRegion, &amp;clipBounds);
</span><span class="cx">                     OffsetRgn(clipRegion, -clipBounds.left, -clipBounds.top);
</span><del>-                    port = nPort.qdPort.port;
</del><span class="cx">                 }
</span><span class="cx">             }
</span><del>-    
</del><ins>+
</ins><span class="cx">             // Switch to the port and set it up.
</span><span class="cx">             SetPort(port);
</span><span class="cx">             PenNormal();
</span><span class="lines">@@ -497,40 +513,51 @@
</span><span class="cx"> 
</span><span class="cx">                 // Some plugins do their own BeginUpdate/EndUpdate.
</span><span class="cx">                 // For those, we must make sure that the update region contains the area we want to draw.
</span><del>-                if (offScreenContext)
</del><ins>+                if (port == offscreenGWorld)
</ins><span class="cx">                     OffsetRgn(clipRegion, clipBounds.left, clipBounds.top);
</span><span class="cx">                 InvalWindowRgn(windowRef, clipRegion);
</span><span class="cx">             }
</span><span class="cx">             
</span><span class="cx">             qdPortState-&gt;forUpdate = forUpdate;
</span><del>-
</del><ins>+            break;
</ins><span class="cx">         }
</span><del>-        break;
</del><span class="cx"> #endif /* NP_NO_QUICKDRAW */
</span><del>-        
-        case NPDrawingModelCoreGraphics:
-        {            
</del><ins>+
+        case NPDrawingModelCoreGraphics: {            
</ins><span class="cx">             // A CoreGraphics plugin's window may only be set while the plugin view is being updated
</span><span class="cx">             ASSERT(forUpdate &amp;&amp; [NSView focusView] == self);
</span><span class="cx"> 
</span><ins>+            CGContextRef context = static_cast&lt;CGContextRef&gt;([[NSGraphicsContext currentContext] graphicsPort]);
+
</ins><span class="cx">             PortState_CG *cgPortState = (PortState_CG *)malloc(sizeof(PortState_CG));
</span><span class="cx">             portState = (PortState)cgPortState;
</span><del>-            cgPortState-&gt;context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
</del><ins>+            cgPortState-&gt;context = context;
</ins><span class="cx">             
</span><span class="cx">             // Update the plugin's window/context
</span><span class="cx">             nPort.cgPort.window = windowRef;
</span><del>-            nPort.cgPort.context = cgPortState-&gt;context;
</del><ins>+            nPort.cgPort.context = context;
</ins><span class="cx">             window.window = &amp;nPort.cgPort;
</span><span class="cx"> 
</span><span class="cx">             // Save current graphics context's state; will be restored by -restorePortState:
</span><del>-            CGContextSaveGState(nPort.cgPort.context);
</del><ins>+            CGContextSaveGState(context);
</ins><span class="cx">             
</span><del>-            // FIXME (4544971): Clip to dirty region when updating in &quot;windowless&quot; mode (transparent), like in the QD case
</del><ins>+            // Get list of dirty rects from the opaque ancestor -- WebKit does some tricks with invalidation and
+            // display to enable z-ordering for NSViews; a side-effect of this is that only the WebHTMLView
+            // knows about the true set of dirty rects.
+            NSView *opaqueAncestor = [self opaqueAncestor];
+            const NSRect *dirtyRects;
+            int count;
+            [opaqueAncestor getRectsBeingDrawn:&amp;dirtyRects count:&amp;count];
+            Vector&lt;CGRect, 16&gt; convertedDirtyRects;
+            convertedDirtyRects.resize(count);
+            for (int i = 0; i &lt; count; ++i)
+                reinterpret_cast&lt;NSRect&amp;&gt;(convertedDirtyRects[i]) = [self convertRect:dirtyRects[i] fromView:opaqueAncestor];
+            CGContextClipToRects(context, convertedDirtyRects.data(), count);
+
+            break;
</ins><span class="cx">         }
</span><del>-        break;
-        
-        case NPDrawingModelOpenGL:
-        {
</del><ins>+
+        case NPDrawingModelOpenGL: {
</ins><span class="cx">             // An OpenGL plugin's window may only be set while the plugin view is being updated
</span><span class="cx">             ASSERT(forUpdate &amp;&amp; [NSView focusView] == self);
</span><span class="cx"> 
</span><span class="lines">@@ -558,28 +585,29 @@
</span><span class="cx">             // Adjust viewport according to clip
</span><span class="cx">             switch (window.type) {
</span><span class="cx">                 case NPWindowTypeWindow:
</span><del>-                    glViewport(static_cast&lt;GLint&gt;(NSMinX(boundsInWindow) - NSMinX(visibleRectInWindow)), static_cast&lt;GLint&gt;(NSMaxY(visibleRectInWindow) - NSMaxY(boundsInWindow)), window.width, window.height);
-                break;
</del><ins>+                    glViewport(static_cast&lt;GLint&gt;(NSMinX(boundsInWindow) - NSMinX(visibleRectInWindow)),
+                        static_cast&lt;GLint&gt;(NSMaxY(visibleRectInWindow) - NSMaxY(boundsInWindow)),
+                            window.width, window.height);
+                    break;
</ins><span class="cx">                 
</span><del>-                case NPWindowTypeDrawable:
-                {
</del><ins>+                case NPWindowTypeDrawable: {
</ins><span class="cx">                     GLsizei width, height;
</span><span class="cx">                     if ([self _getAGLOffscreenBuffer:NULL width:&amp;width height:&amp;height])
</span><span class="cx">                         glViewport(0, 0, width, height);
</span><ins>+                    break;
</ins><span class="cx">                 }
</span><del>-                break;
</del><span class="cx">                 
</span><span class="cx">                 default:
</span><span class="cx">                     ASSERT_NOT_REACHED();
</span><del>-                break;
</del><ins>+                    break;
</ins><span class="cx">             }
</span><ins>+            break;
</ins><span class="cx">         }
</span><del>-        break;
</del><span class="cx">         
</span><span class="cx">         default:
</span><span class="cx">             ASSERT_NOT_REACHED();
</span><span class="cx">             portState = NULL;
</span><del>-        break;
</del><ins>+            break;
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     return portState;
</span><span class="lines">@@ -597,27 +625,16 @@
</span><span class="cx">     
</span><span class="cx">     switch (drawingModel) {
</span><span class="cx"> #ifndef NP_NO_QUICKDRAW
</span><del>-        case NPDrawingModelQuickDraw:
-        {
-            CGContextRef currentContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
-            
-            // If the current context is an offscreen bitmap, then we need to
-            // dispose its GWorld and restore the Window's GWorld
-            if (currentContext &amp;&amp; WKCGContextIsBitmapContext(currentContext)) {
-                GWorldPtr curGWorld;
-                GetGWorld(&amp;curGWorld, NULL);
-                DisposeGWorld(curGWorld);
-                WindowRef windowRef = (WindowRef)[[self currentWindow] windowRef];
-                CGrafPtr port = GetWindowPort(windowRef);
-                SetGWorld(port, NULL);
-            }
-
</del><ins>+        case NPDrawingModelQuickDraw: {
</ins><span class="cx">             PortState_QD *qdPortState = (PortState_QD *)portState;
</span><span class="cx">             WindowRef windowRef = (WindowRef)[[self currentWindow] windowRef];
</span><span class="cx">             CGrafPtr port = GetWindowPort(windowRef);
</span><ins>+
+            SetPort(port);
+
</ins><span class="cx">             if (qdPortState-&gt;forUpdate)
</span><span class="cx">                 ValidWindowRgn(windowRef, qdPortState-&gt;clipRegion);
</span><del>-            
</del><ins>+
</ins><span class="cx">             SetOrigin(qdPortState-&gt;oldOrigin.h, qdPortState-&gt;oldOrigin.v);
</span><span class="cx"> 
</span><span class="cx">             SetPortClipRegion(port, qdPortState-&gt;oldClipRegion);
</span><span class="lines">@@ -628,26 +645,24 @@
</span><span class="cx">             DisposeRgn(qdPortState-&gt;oldVisibleRegion);
</span><span class="cx">             DisposeRgn(qdPortState-&gt;clipRegion);
</span><span class="cx"> 
</span><del>-            SetGWorld(qdPortState-&gt;oldPort, NULL);
</del><ins>+            SetGWorld(qdPortState-&gt;oldPort, qdPortState-&gt;oldDevice);
+            break;
</ins><span class="cx">         }
</span><del>-        break;
</del><span class="cx"> #endif /* NP_NO_QUICKDRAW */
</span><span class="cx">         
</span><span class="cx">         case NPDrawingModelCoreGraphics:
</span><del>-        {
</del><span class="cx">             ASSERT([NSView focusView] == self);
</span><span class="cx">             ASSERT(((PortState_CG *)portState)-&gt;context == nPort.cgPort.context);
</span><span class="cx">             CGContextRestoreGState(nPort.cgPort.context);
</span><del>-        }
-        break;
</del><ins>+            break;
</ins><span class="cx">         
</span><span class="cx">         case NPDrawingModelOpenGL:
</span><span class="cx">             aglSetCurrentContext(((PortState_GL *)portState)-&gt;oldContext);
</span><del>-        break;
</del><ins>+            break;
</ins><span class="cx">         
</span><span class="cx">         default:
</span><span class="cx">             ASSERT_NOT_REACHED();
</span><del>-        break;
</del><ins>+            break;
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1584,8 +1599,13 @@
</span><span class="cx">     return nil;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (void)freeAttributeKeysAndValues
</del><ins>+- (void)fini
</ins><span class="cx"> {
</span><ins>+#ifndef NP_NO_QUICKDRAW
+    if (offscreenGWorld)
+        DisposeGWorld(offscreenGWorld);
+#endif
+
</ins><span class="cx">     unsigned i;
</span><span class="cx">     for (i = 0; i &lt; argsCount; i++) {
</span><span class="cx">         free(cAttributes[i]);
</span><span class="lines">@@ -1619,7 +1639,7 @@
</span><span class="cx">     ASSERT(!aglWindow);
</span><span class="cx">     ASSERT(!aglContext);
</span><span class="cx"> 
</span><del>-    [self freeAttributeKeysAndValues];
</del><ins>+    [self fini];
</ins><span class="cx"> 
</span><span class="cx">     [super dealloc];
</span><span class="cx"> }
</span><span class="lines">@@ -1629,7 +1649,7 @@
</span><span class="cx">     ASSERT_MAIN_THREAD();
</span><span class="cx">     ASSERT(!isStarted);
</span><span class="cx"> 
</span><del>-    [self freeAttributeKeysAndValues];
</del><ins>+    [self fini];
</ins><span class="cx"> 
</span><span class="cx">     [super finalize];
</span><span class="cx"> }
</span><span class="lines">@@ -1675,12 +1695,6 @@
</span><span class="cx">             CGContextRestoreGState(cgContext);
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-    
-    // Set the CG clip path to the plug-in dirty rect. This allows plug-ins to obtain their dirty rect using
-    // functions like CGContextGetClipBoundingBox().
-    if (drawingModel == NPDrawingModelCoreGraphics) 
-        CGContextClipToRect((CGContextRef)[[NSGraphicsContext currentContext] graphicsPort], (CGRect &amp;)rect);
-       
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (BOOL)isFlipped
</span></span></pre>
</div>
</div>

</body>
</html>