--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -478,16 +478,18 @@ public:
nsIObserver* aObserver) override;
// Mac specific methods
virtual bool DispatchWindowEvent(mozilla::WidgetGUIEvent& event);
void WillPaintWindow();
bool PaintWindow(LayoutDeviceIntRegion aRegion);
+ bool PaintWindowInContext(CGContextRef aContext, const LayoutDeviceIntRegion& aRegion,
+ mozilla::gfx::IntSize aSurfaceSize);
#ifdef ACCESSIBILITY
already_AddRefed<mozilla::a11y::Accessible> GetDocumentAccessible();
#endif
virtual void CreateCompositor() override;
virtual void PrepareWindowEffects() override;
virtual void CleanupWindowEffects() override;
@@ -682,16 +684,19 @@ protected:
// Used in OMTC BasicLayers mode. Presents the BasicCompositor result
// surface to the screen using an OpenGL context.
nsAutoPtr<GLPresenter> mGLPresenter;
mozilla::UniquePtr<mozilla::VibrancyManager> mVibrancyManager;
RefPtr<mozilla::SwipeTracker> mSwipeTracker;
mozilla::UniquePtr<mozilla::SwipeEventQueue> mSwipeEventQueue;
+ // Only used for drawRect-based painting in popups.
+ RefPtr<mozilla::gfx::DrawTarget> mBackingSurface;
+
// This flag is only used when APZ is off. It indicates that the current pan
// gesture was processed as a swipe. Sometimes the swipe animation can finish
// before momentum events of the pan gesture have stopped firing, so this
// flag tells us that we shouldn't allow the remaining events to cause
// scrolling. It is reset to false once a new gesture starts (as indicated by
// a PANGESTURE_(MAY)START event).
bool mCurrentPanGestureBelongsToSwipe;
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -92,16 +92,17 @@
#include "nsLayoutUtils.h"
#include "InputData.h"
#include "SwipeTracker.h"
#include "VibrancyManager.h"
#include "nsNativeThemeCocoa.h"
#include "nsIDOMWindowUtils.h"
#include "Units.h"
#include "UnitTransforms.h"
+#include "mozilla/UniquePtrExtensions.h"
using namespace mozilla;
using namespace mozilla::layers;
using namespace mozilla::gl;
using namespace mozilla::widget;
using mozilla::gfx::Matrix4x4;
@@ -1528,16 +1529,81 @@ bool nsChildView::PaintWindow(LayoutDevi
if (listener) {
listener->DidPaintWindow();
}
mIsDispatchPaint = oldDispatchPaint;
return returnValue;
}
+bool
+nsChildView::PaintWindowInContext(CGContextRef aContext, const LayoutDeviceIntRegion& aRegion, gfx::IntSize aSurfaceSize)
+{
+ if (!mBackingSurface || mBackingSurface->GetSize() != aSurfaceSize) {
+ mBackingSurface =
+ gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(aSurfaceSize,
+ gfx::SurfaceFormat::B8G8R8A8);
+ if (!mBackingSurface) {
+ return false;
+ }
+ }
+
+ RefPtr<gfxContext> targetContext = gfxContext::ForDrawTarget(mBackingSurface);
+ MOZ_ASSERT(targetContext); // already checked the draw target above
+
+ // Set up the clip region and clear existing contents in the backing surface.
+ targetContext->NewPath();
+ for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
+ const LayoutDeviceIntRect& r = iter.Get();
+ targetContext->Rectangle(gfxRect(r.x, r.y, r.width, r.height));
+ mBackingSurface->ClearRect(gfx::Rect(r.ToUnknownRect()));
+ }
+ targetContext->Clip();
+
+ nsAutoRetainCocoaObject kungFuDeathGrip(mView);
+ bool painted = false;
+ if (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_BASIC) {
+ nsBaseWidget::AutoLayerManagerSetup
+ setupLayerManager(this, targetContext, BufferMode::BUFFER_NONE);
+ painted = PaintWindow(aRegion);
+ } else if (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
+ // We only need this so that we actually get DidPaintWindow fired
+ painted = PaintWindow(aRegion);
+ }
+
+ uint8_t* data;
+ gfx::IntSize size;
+ int32_t stride;
+ gfx::SurfaceFormat format;
+
+ if (!mBackingSurface->LockBits(&data, &size, &stride, &format)) {
+ return false;
+ }
+
+ // Draw the backing surface onto the window.
+ CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, data, stride * size.height, NULL);
+ NSColorSpace* colorSpace = [[mView window] colorSpace];
+ CGImageRef image = CGImageCreate(size.width, size.height, 8, 32, stride,
+ [colorSpace CGColorSpace],
+ kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst,
+ provider, NULL, false, kCGRenderingIntentDefault);
+ CGContextSaveGState(aContext);
+ CGContextTranslateCTM(aContext, 0, size.height);
+ CGContextScaleCTM(aContext, 1, -1);
+ CGContextSetBlendMode(aContext, kCGBlendModeCopy);
+ CGContextDrawImage(aContext, CGRectMake(0, 0, size.width, size.height), image);
+ CGImageRelease(image);
+ CGDataProviderRelease(provider);
+ CGContextRestoreGState(aContext);
+
+ mBackingSurface->ReleaseBits(data);
+
+ return painted;
+}
+
#pragma mark -
void nsChildView::ReportMoveEvent()
{
NotifyWindowMoved(mBounds.x, mBounds.y);
}
void nsChildView::ReportSizeEvent()
@@ -3778,60 +3844,19 @@ NSEvent* gLastDragMouseDownEvent = nil;
// multiple dev pixels. But Gecko expects its supplied context to be scaled
// to device pixels, so we need to reverse the scaling.
double scale = mGeckoChild->BackingScaleFactor();
CGContextSaveGState(aContext);
CGContextScaleCTM(aContext, 1.0 / scale, 1.0 / scale);
NSSize viewSize = [self bounds].size;
nsIntSize backingSize(viewSize.width * scale, viewSize.height * scale);
-
- CGContextSaveGState(aContext);
-
LayoutDeviceIntRegion region = [self nativeDirtyRegionWithBoundingRect:aRect];
- // Create Cairo objects.
- RefPtr<gfxQuartzSurface> targetSurface;
-
- RefPtr<gfx::DrawTarget> dt =
- gfx::Factory::CreateDrawTargetForCairoCGContext(aContext,
- gfx::IntSize(backingSize.width,
- backingSize.height));
- if (!dt || !dt->IsValid()) {
- // This used to be an assertion, so keep crashing in nightly+aurora
- gfxDevCrash(mozilla::gfx::LogReason::InvalidContext) << "Cannot create target with CreateDrawTargetForCairoCGContext " << backingSize;
- return;
- }
- dt->AddUserData(&gfxContext::sDontUseAsSourceKey, dt, nullptr);
- RefPtr<gfxContext> targetContext = gfxContext::ForDrawTarget(dt);
- MOZ_ASSERT(targetContext); // already checked the draw target above
-
- // Set up the clip region.
- targetContext->NewPath();
- for (auto iter = region.RectIter(); !iter.Done(); iter.Next()) {
- const LayoutDeviceIntRect& r = iter.Get();
- targetContext->Rectangle(gfxRect(r.x, r.y, r.width, r.height));
- }
- targetContext->Clip();
-
- nsAutoRetainCocoaObject kungFuDeathGrip(self);
- bool painted = false;
- if (mGeckoChild->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_BASIC) {
- nsBaseWidget::AutoLayerManagerSetup
- setupLayerManager(mGeckoChild, targetContext, BufferMode::BUFFER_NONE);
- painted = mGeckoChild->PaintWindow(region);
- } else if (mGeckoChild->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
- // We only need this so that we actually get DidPaintWindow fired
- painted = mGeckoChild->PaintWindow(region);
- }
-
- targetContext = nullptr;
- targetSurface = nullptr;
-
- CGContextRestoreGState(aContext);
+ bool painted = mGeckoChild->PaintWindowInContext(aContext, region, backingSize);
// Undo the scale transform so that from now on the context is in
// CocoaPoints again.
CGContextRestoreGState(aContext);
if (!painted && [self isOpaque]) {
// Gecko refused to draw, but we've claimed to be opaque, so we have to
// draw something--fill with white.