mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 676241 part 6/9/11: Correct titlebar drawing. r=bgirard, r=smichaud, r=mattwoodrow
This commit is contained in:
parent
0a085125ca
commit
e3ca87e242
@ -279,6 +279,10 @@ typedef NSInteger NSEventGestureAxis;
|
|||||||
|
|
||||||
// Whether this uses off-main-thread compositing.
|
// Whether this uses off-main-thread compositing.
|
||||||
BOOL mUsingOMTCompositor;
|
BOOL mUsingOMTCompositor;
|
||||||
|
|
||||||
|
// The mask image that's used when painting into the titlebar using basic
|
||||||
|
// CGContext painting (i.e. non-accelerated).
|
||||||
|
CGImageRef mTopLeftCornerMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
// class initialization
|
// class initialization
|
||||||
@ -316,6 +320,8 @@ typedef NSInteger NSEventGestureAxis;
|
|||||||
- (void)setGLContext:(NSOpenGLContext *)aGLContext;
|
- (void)setGLContext:(NSOpenGLContext *)aGLContext;
|
||||||
- (void)preRender:(NSOpenGLContext *)aGLContext;
|
- (void)preRender:(NSOpenGLContext *)aGLContext;
|
||||||
|
|
||||||
|
- (BOOL)isCoveringTitlebar;
|
||||||
|
|
||||||
// Simple gestures support
|
// Simple gestures support
|
||||||
//
|
//
|
||||||
// XXX - The swipeWithEvent, beginGestureWithEvent, magnifyWithEvent,
|
// XXX - The swipeWithEvent, beginGestureWithEvent, magnifyWithEvent,
|
||||||
@ -538,6 +544,8 @@ public:
|
|||||||
return mTextInputHandler;
|
return mTextInputHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NotifyDirtyRegion(const nsIntRegion& aDirtyRegion);
|
||||||
|
|
||||||
// unit conversion convenience functions
|
// unit conversion convenience functions
|
||||||
int32_t CocoaPointsToDevPixels(CGFloat aPts) {
|
int32_t CocoaPointsToDevPixels(CGFloat aPts) {
|
||||||
return nsCocoaUtils::CocoaPointsToDevPixels(aPts, BackingScaleFactor());
|
return nsCocoaUtils::CocoaPointsToDevPixels(aPts, BackingScaleFactor());
|
||||||
@ -573,8 +581,20 @@ protected:
|
|||||||
return widget.forget();
|
return widget.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaybeDrawResizeIndicator(mozilla::layers::GLManager* aManager, nsIntRect aRect);
|
// Overlay drawing functions for OpenGL drawing
|
||||||
void MaybeDrawRoundedBottomCorners(mozilla::layers::GLManager* aManager, nsIntRect aRect);
|
void MaybeDrawResizeIndicator(mozilla::layers::GLManager* aManager, const nsIntRect& aRect);
|
||||||
|
void MaybeDrawRoundedCorners(mozilla::layers::GLManager* aManager, const nsIntRect& aRect);
|
||||||
|
void MaybeDrawTitlebar(mozilla::layers::GLManager* aManager, const nsIntRect& aRect);
|
||||||
|
|
||||||
|
// Redraw the contents of mTitlebarImageBuffer on the main thread, as
|
||||||
|
// determined by mDirtyTitlebarRegion.
|
||||||
|
void UpdateTitlebarImageBuffer();
|
||||||
|
|
||||||
|
// Upload the contents of mTitlebarImageBuffer to mTitlebarImage on the
|
||||||
|
// compositor thread, as determined by mUpdatedTitlebarRegion.
|
||||||
|
void UpdateTitlebarImage(mozilla::layers::GLManager* aManager, const nsIntRect& aRect);
|
||||||
|
|
||||||
|
nsIntRect RectContainingTitlebarControls();
|
||||||
|
|
||||||
nsIWidget* GetWidgetForListenerEvents();
|
nsIWidget* GetWidgetForListenerEvents();
|
||||||
|
|
||||||
@ -604,12 +624,25 @@ protected:
|
|||||||
nsIntRect mResizeIndicatorRect;
|
nsIntRect mResizeIndicatorRect;
|
||||||
bool mHasRoundedBottomCorners;
|
bool mHasRoundedBottomCorners;
|
||||||
int mDevPixelCornerRadius;
|
int mDevPixelCornerRadius;
|
||||||
|
bool mIsCoveringTitlebar;
|
||||||
|
nsIntRect mTitlebarRect;
|
||||||
|
|
||||||
|
// The area of mTitlebarImageBuffer that needs to be redrawn during the next
|
||||||
|
// transaction. Accessed from any thread, protected by mEffectsLock.
|
||||||
|
nsIntRegion mUpdatedTitlebarRegion;
|
||||||
|
|
||||||
|
nsRefPtr<gfxQuartzSurface> mTitlebarImageBuffer;
|
||||||
|
|
||||||
// Compositor thread only
|
// Compositor thread only
|
||||||
bool mFailedResizerImage;
|
bool mFailedResizerImage;
|
||||||
bool mFailedCornerMaskImage;
|
bool mFailedCornerMaskImage;
|
||||||
nsRefPtr<mozilla::gl::TextureImage> mResizerImage;
|
nsRefPtr<mozilla::gl::TextureImage> mResizerImage;
|
||||||
nsRefPtr<mozilla::gl::TextureImage> mCornerMaskImage;
|
nsRefPtr<mozilla::gl::TextureImage> mCornerMaskImage;
|
||||||
|
nsRefPtr<mozilla::gl::TextureImage> mTitlebarImage;
|
||||||
|
|
||||||
|
// The area of mTitlebarImageBuffer that has changed and needs to be
|
||||||
|
// uploaded to to mTitlebarImage. Main thread only.
|
||||||
|
nsIntRegion mDirtyTitlebarRegion;
|
||||||
|
|
||||||
// Cached value of [mView backingScaleFactor], to avoid sending two obj-c
|
// Cached value of [mView backingScaleFactor], to avoid sending two obj-c
|
||||||
// messages (respondsToSelector, backingScaleFactor) every time we need to
|
// messages (respondsToSelector, backingScaleFactor) every time we need to
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
|
|
||||||
#include "gfxContext.h"
|
#include "gfxContext.h"
|
||||||
#include "gfxQuartzSurface.h"
|
#include "gfxQuartzSurface.h"
|
||||||
|
#include "gfxUtils.h"
|
||||||
#include "nsRegion.h"
|
#include "nsRegion.h"
|
||||||
#include "Layers.h"
|
#include "Layers.h"
|
||||||
#include "LayerManagerOGL.h"
|
#include "LayerManagerOGL.h"
|
||||||
@ -146,8 +147,12 @@ uint32_t nsChildView::sLastInputEventCount = 0;
|
|||||||
- (void)drawUsingOpenGLCallback;
|
- (void)drawUsingOpenGLCallback;
|
||||||
|
|
||||||
- (BOOL)hasRoundedBottomCorners;
|
- (BOOL)hasRoundedBottomCorners;
|
||||||
- (CGFloat)bottomCornerRadius;
|
- (CGFloat)cornerRadius;
|
||||||
- (void)maybeClearBottomCorners;
|
- (void)clearCorners;
|
||||||
|
|
||||||
|
// Overlay drawing functions for traditional CGContext drawing
|
||||||
|
- (void)drawTitlebarHighlight;
|
||||||
|
- (void)maskTopCornersInContext:(CGContextRef)aContext;
|
||||||
|
|
||||||
// Called using performSelector:withObject:afterDelay:0 to release
|
// Called using performSelector:withObject:afterDelay:0 to release
|
||||||
// aWidgetArray (and its contents) the next time through the run loop.
|
// aWidgetArray (and its contents) the next time through the run loop.
|
||||||
@ -246,6 +251,7 @@ nsChildView::nsChildView() : nsBaseWidget()
|
|||||||
, mEffectsLock("WidgetEffects")
|
, mEffectsLock("WidgetEffects")
|
||||||
, mShowsResizeIndicator(false)
|
, mShowsResizeIndicator(false)
|
||||||
, mHasRoundedBottomCorners(false)
|
, mHasRoundedBottomCorners(false)
|
||||||
|
, mIsCoveringTitlebar(false)
|
||||||
, mFailedResizerImage(false)
|
, mFailedResizerImage(false)
|
||||||
, mFailedCornerMaskImage(false)
|
, mFailedCornerMaskImage(false)
|
||||||
, mBackingScaleFactor(0.0)
|
, mBackingScaleFactor(0.0)
|
||||||
@ -1815,15 +1821,45 @@ nsChildView::GetThebesSurface()
|
|||||||
return mTempThebesSurface;
|
return mTempThebesSurface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsChildView::NotifyDirtyRegion(const nsIntRegion& aDirtyRegion)
|
||||||
|
{
|
||||||
|
if ([(ChildView*)mView isCoveringTitlebar]) {
|
||||||
|
// We store the dirty region so that we know what to repaint in the titlebar.
|
||||||
|
mDirtyTitlebarRegion.Or(mDirtyTitlebarRegion, aDirtyRegion);
|
||||||
|
mDirtyTitlebarRegion.And(mDirtyTitlebarRegion, RectContainingTitlebarControls());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const CGFloat kTitlebarHighlightHeight = 6;
|
||||||
|
|
||||||
|
nsIntRect
|
||||||
|
nsChildView::RectContainingTitlebarControls()
|
||||||
|
{
|
||||||
|
// Start with a 6px high strip at the top of the window for the highlight line.
|
||||||
|
NSRect rect = NSMakeRect(0, 0, [mView bounds].size.width,
|
||||||
|
kTitlebarHighlightHeight);
|
||||||
|
|
||||||
|
// Add the rects of the titlebar controls.
|
||||||
|
for (id view in [(BaseWindow*)[mView window] titlebarControls]) {
|
||||||
|
rect = NSUnionRect(rect, [mView convertRect:[view bounds] fromView:view]);
|
||||||
|
}
|
||||||
|
return CocoaPointsToDevPixels(rect);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsChildView::PrepareWindowEffects()
|
nsChildView::PrepareWindowEffects()
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(mEffectsLock);
|
MutexAutoLock lock(mEffectsLock);
|
||||||
mShowsResizeIndicator = ShowsResizeIndicator(&mResizeIndicatorRect);
|
mShowsResizeIndicator = ShowsResizeIndicator(&mResizeIndicatorRect);
|
||||||
mHasRoundedBottomCorners = [mView isKindOfClass:[ChildView class]] &&
|
mHasRoundedBottomCorners = [(ChildView*)mView hasRoundedBottomCorners];
|
||||||
[(ChildView*)mView hasRoundedBottomCorners];
|
CGFloat cornerRadius = [(ChildView*)mView cornerRadius];
|
||||||
CGFloat cornerRadius = [(ChildView*)mView bottomCornerRadius];
|
|
||||||
mDevPixelCornerRadius = cornerRadius * BackingScaleFactor();
|
mDevPixelCornerRadius = cornerRadius * BackingScaleFactor();
|
||||||
|
mIsCoveringTitlebar = [(ChildView*)mView isCoveringTitlebar];
|
||||||
|
if (mIsCoveringTitlebar) {
|
||||||
|
mTitlebarRect = RectContainingTitlebarControls();
|
||||||
|
UpdateTitlebarImageBuffer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1831,6 +1867,7 @@ nsChildView::CleanupWindowEffects()
|
|||||||
{
|
{
|
||||||
mResizerImage = nullptr;
|
mResizerImage = nullptr;
|
||||||
mCornerMaskImage = nullptr;
|
mCornerMaskImage = nullptr;
|
||||||
|
mTitlebarImage = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1852,8 +1889,22 @@ nsChildView::DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
manager->gl()->PushScissorRect(aRect);
|
||||||
|
|
||||||
|
MaybeDrawTitlebar(manager, aRect);
|
||||||
MaybeDrawResizeIndicator(manager, aRect);
|
MaybeDrawResizeIndicator(manager, aRect);
|
||||||
MaybeDrawRoundedBottomCorners(manager, aRect);
|
MaybeDrawRoundedCorners(manager, aRect);
|
||||||
|
|
||||||
|
manager->gl()->PopScissorRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ClearRegion(gfxASurface* aSurface, nsIntRegion aRegion)
|
||||||
|
{
|
||||||
|
nsRefPtr<gfxContext> ctx = new gfxContext(aSurface);
|
||||||
|
gfxUtils::ClipToRegion(ctx, aRegion);
|
||||||
|
ctx->SetOperator(gfxContext::OPERATOR_CLEAR);
|
||||||
|
ctx->Paint();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1890,14 +1941,14 @@ DrawResizer(CGContextRef aCtx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsChildView::MaybeDrawResizeIndicator(GLManager* aManager, nsIntRect aRect)
|
nsChildView::MaybeDrawResizeIndicator(GLManager* aManager, const nsIntRect& aRect)
|
||||||
{
|
{
|
||||||
|
MutexAutoLock lock(mEffectsLock);
|
||||||
if (!mShowsResizeIndicator || mFailedResizerImage) {
|
if (!mShowsResizeIndicator || mFailedResizerImage) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mResizerImage) {
|
if (!mResizerImage) {
|
||||||
MutexAutoLock lock(mEffectsLock);
|
|
||||||
mResizerImage =
|
mResizerImage =
|
||||||
aManager->gl()->CreateTextureImage(nsIntSize(mResizeIndicatorRect.width,
|
aManager->gl()->CreateTextureImage(nsIntSize(mResizeIndicatorRect.width,
|
||||||
mResizeIndicatorRect.height),
|
mResizeIndicatorRect.height),
|
||||||
@ -1916,17 +1967,18 @@ nsChildView::MaybeDrawResizeIndicator(GLManager* aManager, nsIntRect aRect)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// is the CairoSurface of a non QuartzSurface usable in the gfxQuartzSurface constructor ?
|
// We need a Quartz surface because DrawResizer wants a CGContext.
|
||||||
// answer seems to be NO (see comments on bug 675410
|
|
||||||
// this should not work for instance: new gfxQuartzSurface(asurf->CairoSurface(), false))
|
|
||||||
if (asurf->GetType() != gfxASurface::SurfaceTypeQuartz) {
|
if (asurf->GetType() != gfxASurface::SurfaceTypeQuartz) {
|
||||||
NS_WARN_IF_FALSE(FALSE, "mResizerImage's surface is not Quartz");
|
NS_WARN_IF_FALSE(FALSE, "mResizerImage's surface is not Quartz");
|
||||||
|
mResizerImage->EndUpdate();
|
||||||
mResizerImage = nullptr;
|
mResizerImage = nullptr;
|
||||||
mFailedResizerImage = true;
|
mFailedResizerImage = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nsRefPtr<gfxQuartzSurface> image = static_cast<gfxQuartzSurface*>(asurf);
|
|
||||||
|
|
||||||
|
ClearRegion(asurf, update);
|
||||||
|
|
||||||
|
nsRefPtr<gfxQuartzSurface> image = static_cast<gfxQuartzSurface*>(asurf);
|
||||||
DrawResizer(image->GetCGContext());
|
DrawResizer(image->GetCGContext());
|
||||||
|
|
||||||
mResizerImage->EndUpdate();
|
mResizerImage->EndUpdate();
|
||||||
@ -1934,8 +1986,8 @@ nsChildView::MaybeDrawResizeIndicator(GLManager* aManager, nsIntRect aRect)
|
|||||||
|
|
||||||
NS_ABORT_IF_FALSE(mResizerImage, "Must have a texture allocated by now!");
|
NS_ABORT_IF_FALSE(mResizerImage, "Must have a texture allocated by now!");
|
||||||
|
|
||||||
float bottomX = aRect.x + aRect.width;
|
float bottomX = aRect.XMost();
|
||||||
float bottomY = aRect.y + aRect.height;
|
float bottomY = aRect.YMost();
|
||||||
|
|
||||||
TextureImage::ScopedBindTexture texBind(mResizerImage, LOCAL_GL_TEXTURE0);
|
TextureImage::ScopedBindTexture texBind(mResizerImage, LOCAL_GL_TEXTURE0);
|
||||||
|
|
||||||
@ -1954,6 +2006,195 @@ nsChildView::MaybeDrawResizeIndicator(GLManager* aManager, nsIntRect aRect)
|
|||||||
aManager->BindAndDrawQuad(program);
|
aManager->BindAndDrawQuad(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw the highlight line at the top of the titlebar.
|
||||||
|
// This function draws into the current NSGraphicsContext and assumes flippedness.
|
||||||
|
static void
|
||||||
|
DrawTitlebarHighlight(NSSize aWindowSize, CGFloat aRadius, CGFloat aDevicePixelWidth)
|
||||||
|
{
|
||||||
|
[NSGraphicsContext saveGraphicsState];
|
||||||
|
|
||||||
|
// Set up the clip path. We start with the outer rectangle and cut out a
|
||||||
|
// slightly smaller inner rectangle with rounded corners.
|
||||||
|
// The outer corners of the resulting path will be square, but they will be
|
||||||
|
// masked away in a later step.
|
||||||
|
NSBezierPath* path = [NSBezierPath bezierPath];
|
||||||
|
[path setWindingRule:NSEvenOddWindingRule];
|
||||||
|
NSRect pathRect = NSMakeRect(0, 0, aWindowSize.width, kTitlebarHighlightHeight + 2);
|
||||||
|
[path appendBezierPathWithRect:pathRect];
|
||||||
|
pathRect = NSInsetRect(pathRect, aDevicePixelWidth, aDevicePixelWidth);
|
||||||
|
CGFloat innerRadius = aRadius - aDevicePixelWidth;
|
||||||
|
[path appendBezierPathWithRoundedRect:pathRect xRadius:innerRadius yRadius:innerRadius];
|
||||||
|
[path addClip];
|
||||||
|
|
||||||
|
// Now we fill the path with a subtle highlight gradient.
|
||||||
|
NSColor* topColor = [NSColor colorWithDeviceWhite:1.0 alpha:0.4];
|
||||||
|
NSColor* bottomColor = [NSColor colorWithDeviceWhite:1.0 alpha:0.0];
|
||||||
|
NSGradient* gradient = [[NSGradient alloc] initWithStartingColor:topColor endingColor:bottomColor];
|
||||||
|
[gradient drawInRect:NSMakeRect(0, 0, aWindowSize.width, kTitlebarHighlightHeight) angle:90];
|
||||||
|
[gradient release];
|
||||||
|
|
||||||
|
[NSGraphicsContext restoreGraphicsState];
|
||||||
|
}
|
||||||
|
|
||||||
|
// When this method is entered, mEffectsLock is already being held.
|
||||||
|
void
|
||||||
|
nsChildView::UpdateTitlebarImageBuffer()
|
||||||
|
{
|
||||||
|
nsIntRegion dirtyTitlebarRegion = mDirtyTitlebarRegion;
|
||||||
|
mDirtyTitlebarRegion.SetEmpty();
|
||||||
|
|
||||||
|
if (!mTitlebarImageBuffer ||
|
||||||
|
mTitlebarImageBuffer->GetSize() != mTitlebarRect.Size()) {
|
||||||
|
dirtyTitlebarRegion = mTitlebarRect;
|
||||||
|
|
||||||
|
mTitlebarImageBuffer = new gfxQuartzSurface(mTitlebarRect.Size(),
|
||||||
|
gfxASurface::ImageFormatARGB32);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dirtyTitlebarRegion.IsEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
ClearRegion(mTitlebarImageBuffer, dirtyTitlebarRegion);
|
||||||
|
|
||||||
|
CGContextRef ctx = mTitlebarImageBuffer->GetCGContext();
|
||||||
|
|
||||||
|
double scale = BackingScaleFactor();
|
||||||
|
CGContextScaleCTM(ctx, scale, scale);
|
||||||
|
NSGraphicsContext* oldContext = [NSGraphicsContext currentContext];
|
||||||
|
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:YES]];
|
||||||
|
|
||||||
|
CGContextSaveGState(ctx);
|
||||||
|
|
||||||
|
BaseWindow* window = (BaseWindow*)[mView window];
|
||||||
|
NSView* frameView = [[window contentView] superview];
|
||||||
|
if (![frameView isFlipped]) {
|
||||||
|
CGContextTranslateCTM(ctx, 0, [frameView bounds].size.height);
|
||||||
|
CGContextScaleCTM(ctx, 1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the titlebar controls into the titlebar image.
|
||||||
|
for (id view in [window titlebarControls]) {
|
||||||
|
NSRect viewFrame = [view frame];
|
||||||
|
nsIntRect viewRect = CocoaPointsToDevPixels([mView convertRect:viewFrame fromView:frameView]);
|
||||||
|
nsIntRegion intersection;
|
||||||
|
intersection.And(dirtyTitlebarRegion, viewRect);
|
||||||
|
if (intersection.IsEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// All of the titlebar controls we're interested in are subclasses of
|
||||||
|
// NSButton.
|
||||||
|
if (![view isKindOfClass:[NSButton class]]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
NSButton *button = (NSButton *) view;
|
||||||
|
id cellObject = [button cell];
|
||||||
|
if (![cellObject isKindOfClass:[NSCell class]]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
NSCell *cell = (NSCell *) cellObject;
|
||||||
|
|
||||||
|
CGContextSaveGState(ctx);
|
||||||
|
CGContextTranslateCTM(ctx, viewFrame.origin.x, viewFrame.origin.y);
|
||||||
|
|
||||||
|
if ([view isFlipped]) {
|
||||||
|
CGContextTranslateCTM(ctx, 0, viewFrame.size.height);
|
||||||
|
CGContextScaleCTM(ctx, 1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
NSRect intersectRect = DevPixelsToCocoaPoints(intersection.GetBounds());
|
||||||
|
[cell drawWithFrame:[view convertRect:intersectRect fromView:mView] inView:button];
|
||||||
|
|
||||||
|
CGContextRestoreGState(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
CGContextRestoreGState(ctx);
|
||||||
|
|
||||||
|
DrawTitlebarHighlight([frameView bounds].size, [(ChildView*)mView cornerRadius],
|
||||||
|
DevPixelsToCocoaPoints(1));
|
||||||
|
|
||||||
|
[NSGraphicsContext setCurrentContext:oldContext];
|
||||||
|
|
||||||
|
mUpdatedTitlebarRegion.Or(mUpdatedTitlebarRegion, dirtyTitlebarRegion);
|
||||||
|
}
|
||||||
|
|
||||||
|
// When this method is entered, mEffectsLock is already being held.
|
||||||
|
void
|
||||||
|
nsChildView::UpdateTitlebarImage(GLManager* aManager, const nsIntRect& aRect)
|
||||||
|
{
|
||||||
|
nsIntRegion updatedTitlebarRegion;
|
||||||
|
updatedTitlebarRegion.And(mUpdatedTitlebarRegion, mTitlebarRect);
|
||||||
|
mUpdatedTitlebarRegion.SetEmpty();
|
||||||
|
|
||||||
|
if (!mTitlebarImage || mTitlebarImage->GetSize() != mTitlebarRect.Size()) {
|
||||||
|
updatedTitlebarRegion = mTitlebarRect;
|
||||||
|
|
||||||
|
mTitlebarImage =
|
||||||
|
aManager->gl()->CreateTextureImage(mTitlebarRect.Size(),
|
||||||
|
gfxASurface::CONTENT_COLOR_ALPHA,
|
||||||
|
LOCAL_GL_CLAMP_TO_EDGE,
|
||||||
|
TextureImage::UseNearestFilter);
|
||||||
|
|
||||||
|
// Creation of texture images can fail.
|
||||||
|
if (!mTitlebarImage)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updatedTitlebarRegion.IsEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
gfxASurface *asurf = mTitlebarImage->BeginUpdate(updatedTitlebarRegion);
|
||||||
|
if (!asurf) {
|
||||||
|
mTitlebarImage = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<gfxContext> ctx = new gfxContext(asurf);
|
||||||
|
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||||
|
ctx->SetSource(mTitlebarImageBuffer);
|
||||||
|
ctx->Paint();
|
||||||
|
|
||||||
|
mTitlebarImage->EndUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method draws an overlay in the top of the window which contains the
|
||||||
|
// titlebar controls (e.g. close, min, zoom, fullscreen) and the titlebar
|
||||||
|
// highlight effect.
|
||||||
|
// This is necessary because the real titlebar controls are covered by our
|
||||||
|
// OpenGL context. Note that in terms of the NSView hierarchy, our ChildView
|
||||||
|
// is actually below the titlebar controls - that's why hovering and clicking
|
||||||
|
// them works as expected - but their visual representation is only drawn into
|
||||||
|
// the normal window buffer, and the window buffer surface lies below the
|
||||||
|
// GLContext surface. In order to make the titlebar controls visible, we have
|
||||||
|
// to redraw them inside the OpenGL context surface.
|
||||||
|
void
|
||||||
|
nsChildView::MaybeDrawTitlebar(GLManager* aManager, const nsIntRect& aRect)
|
||||||
|
{
|
||||||
|
MutexAutoLock lock(mEffectsLock);
|
||||||
|
if (!mIsCoveringTitlebar) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateTitlebarImage(aManager, aRect);
|
||||||
|
|
||||||
|
if (!mTitlebarImage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureImage::ScopedBindTexture texBind(mTitlebarImage, LOCAL_GL_TEXTURE0);
|
||||||
|
|
||||||
|
ShaderProgramOGL *program =
|
||||||
|
aManager->GetProgram(mTitlebarImage->GetShaderProgramType());
|
||||||
|
program->Activate();
|
||||||
|
program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0),
|
||||||
|
mTitlebarImage->GetSize()));
|
||||||
|
program->SetLayerTransform(gfx3DMatrix());
|
||||||
|
program->SetLayerOpacity(1.0);
|
||||||
|
program->SetRenderOffset(nsIntPoint(0,0));
|
||||||
|
program->SetTextureUnit(0);
|
||||||
|
|
||||||
|
aManager->BindAndDrawQuad(program);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
DrawTopLeftCornerMask(CGContextRef aCtx, int aRadius)
|
DrawTopLeftCornerMask(CGContextRef aCtx, int aRadius)
|
||||||
{
|
{
|
||||||
@ -1962,14 +2203,14 @@ DrawTopLeftCornerMask(CGContextRef aCtx, int aRadius)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsChildView::MaybeDrawRoundedBottomCorners(GLManager* aManager, nsIntRect aRect)
|
nsChildView::MaybeDrawRoundedCorners(GLManager* aManager, const nsIntRect& aRect)
|
||||||
{
|
{
|
||||||
if (!mHasRoundedBottomCorners ||
|
|
||||||
mFailedCornerMaskImage)
|
|
||||||
return;
|
|
||||||
|
|
||||||
MutexAutoLock lock(mEffectsLock);
|
MutexAutoLock lock(mEffectsLock);
|
||||||
|
|
||||||
|
if (mFailedCornerMaskImage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!mCornerMaskImage) {
|
if (!mCornerMaskImage) {
|
||||||
mCornerMaskImage =
|
mCornerMaskImage =
|
||||||
aManager->gl()->CreateTextureImage(nsIntSize(mDevPixelCornerRadius,
|
aManager->gl()->CreateTextureImage(nsIntSize(mDevPixelCornerRadius,
|
||||||
@ -1988,20 +2229,20 @@ nsChildView::MaybeDrawRoundedBottomCorners(GLManager* aManager, nsIntRect aRect)
|
|||||||
mCornerMaskImage = nullptr;
|
mCornerMaskImage = nullptr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// is the CairoSurface of a non QuartzSurface usable in the gfxQuartzSurface constructor ?
|
|
||||||
// answer seems to be NO (see comments on bug 675410
|
|
||||||
// this should not work for instance: new gfxQuartzSurface(asurf->CairoSurface(), false))
|
|
||||||
if (asurf->GetType() != gfxASurface::SurfaceTypeQuartz) {
|
if (asurf->GetType() != gfxASurface::SurfaceTypeQuartz) {
|
||||||
NS_WARN_IF_FALSE(FALSE, "mCornerMaskImage's surface is not Quartz");
|
NS_WARNING("mCornerMaskImage's surface is not Quartz");
|
||||||
|
mCornerMaskImage->EndUpdate();
|
||||||
mCornerMaskImage = nullptr;
|
mCornerMaskImage = nullptr;
|
||||||
mFailedCornerMaskImage = true;
|
mFailedCornerMaskImage = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClearRegion(asurf, update);
|
||||||
|
|
||||||
nsRefPtr<gfxQuartzSurface> image = static_cast<gfxQuartzSurface*>(asurf);
|
nsRefPtr<gfxQuartzSurface> image = static_cast<gfxQuartzSurface*>(asurf);
|
||||||
|
|
||||||
DrawTopLeftCornerMask(image->GetCGContext(), mDevPixelCornerRadius);
|
DrawTopLeftCornerMask(image->GetCGContext(), mDevPixelCornerRadius);
|
||||||
|
|
||||||
mCornerMaskImage->EndUpdate();
|
mCornerMaskImage->EndUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2011,25 +2252,36 @@ nsChildView::MaybeDrawRoundedBottomCorners(GLManager* aManager, nsIntRect aRect)
|
|||||||
|
|
||||||
ShaderProgramOGL *program = aManager->GetProgram(mCornerMaskImage->GetShaderProgramType());
|
ShaderProgramOGL *program = aManager->GetProgram(mCornerMaskImage->GetShaderProgramType());
|
||||||
program->Activate();
|
program->Activate();
|
||||||
program->SetLayerQuadRect(nsIntRect(0, 0, // aRect.x, aRect.y,
|
program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0),
|
||||||
mDevPixelCornerRadius,
|
mCornerMaskImage->GetSize()));
|
||||||
mDevPixelCornerRadius));
|
|
||||||
program->SetLayerOpacity(1.0);
|
program->SetLayerOpacity(1.0);
|
||||||
program->SetRenderOffset(nsIntPoint(0,0));
|
program->SetRenderOffset(nsIntPoint(0,0));
|
||||||
program->SetTextureUnit(0);
|
program->SetTextureUnit(0);
|
||||||
|
|
||||||
// Use operator destination in: multiply all 4 channels with source alpha.
|
// Use operator destination in: multiply all 4 channels with source alpha.
|
||||||
aManager->gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_SRC_ALPHA,
|
aManager->gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_SRC_ALPHA,
|
||||||
LOCAL_GL_ZERO, LOCAL_GL_SRC_ALPHA);
|
LOCAL_GL_ZERO, LOCAL_GL_SRC_ALPHA);
|
||||||
|
|
||||||
// Draw; first bottom left, then bottom right.
|
if (mIsCoveringTitlebar) {
|
||||||
program->SetLayerTransform(gfx3DMatrix::ScalingMatrix(1, -1, 1) *
|
// Mask the top corners.
|
||||||
gfx3DMatrix::Translation(0, aRect.height, 0));
|
program->SetLayerTransform(gfx3DMatrix::ScalingMatrix(1, 1, 1) *
|
||||||
aManager->BindAndDrawQuad(program);
|
gfx3DMatrix::Translation(0, 0, 0));
|
||||||
program->SetLayerTransform(gfx3DMatrix::ScalingMatrix(-1, -1, 1) *
|
aManager->BindAndDrawQuad(program);
|
||||||
gfx3DMatrix::Translation(aRect.width, aRect.height, 0));
|
program->SetLayerTransform(gfx3DMatrix::ScalingMatrix(-1, 1, 1) *
|
||||||
aManager->BindAndDrawQuad(program);
|
gfx3DMatrix::Translation(aRect.width, 0, 0));
|
||||||
|
aManager->BindAndDrawQuad(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mHasRoundedBottomCorners) {
|
||||||
|
// Mask the bottom corners.
|
||||||
|
program->SetLayerTransform(gfx3DMatrix::ScalingMatrix(1, -1, 1) *
|
||||||
|
gfx3DMatrix::Translation(0, aRect.height, 0));
|
||||||
|
aManager->BindAndDrawQuad(program);
|
||||||
|
program->SetLayerTransform(gfx3DMatrix::ScalingMatrix(-1, -1, 1) *
|
||||||
|
gfx3DMatrix::Translation(aRect.width, aRect.height, 0));
|
||||||
|
aManager->BindAndDrawQuad(program);
|
||||||
|
}
|
||||||
|
|
||||||
// Reset blend mode.
|
// Reset blend mode.
|
||||||
aManager->gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
|
aManager->gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
|
||||||
LOCAL_GL_ONE, LOCAL_GL_ONE);
|
LOCAL_GL_ONE, LOCAL_GL_ONE);
|
||||||
@ -2235,6 +2487,8 @@ NSEvent* gLastDragMouseDownEvent = nil;
|
|||||||
mCancelSwipeAnimation = nil;
|
mCancelSwipeAnimation = nil;
|
||||||
mCurrentSwipeDir = 0;
|
mCurrentSwipeDir = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
mTopLeftCornerMask = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// register for things we'll take from other applications
|
// register for things we'll take from other applications
|
||||||
@ -2335,6 +2589,7 @@ NSEvent* gLastDragMouseDownEvent = nil;
|
|||||||
[mPendingDirtyRects release];
|
[mPendingDirtyRects release];
|
||||||
[mLastMouseDownEvent release];
|
[mLastMouseDownEvent release];
|
||||||
[mClickThroughMouseDownEvent release];
|
[mClickThroughMouseDownEvent release];
|
||||||
|
CGImageRelease(mTopLeftCornerMask);
|
||||||
ChildViewMouseTracker::OnDestroyView(self);
|
ChildViewMouseTracker::OnDestroyView(self);
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
@ -2688,6 +2943,13 @@ NSEvent* gLastDragMouseDownEvent = nil;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)isCoveringTitlebar
|
||||||
|
{
|
||||||
|
return [[self window] isKindOfClass:[BaseWindow class]] &&
|
||||||
|
[(BaseWindow*)[self window] mainChildView] == self &&
|
||||||
|
[(BaseWindow*)[self window] drawsContentsIntoWindowFrame];
|
||||||
|
}
|
||||||
|
|
||||||
// The display system has told us that a portion of our view is dirty. Tell
|
// The display system has told us that a portion of our view is dirty. Tell
|
||||||
// gecko to paint it
|
// gecko to paint it
|
||||||
- (void)drawRect:(NSRect)aRect
|
- (void)drawRect:(NSRect)aRect
|
||||||
@ -2724,31 +2986,14 @@ NSEvent* gLastDragMouseDownEvent = nil;
|
|||||||
fprintf (stderr, " xform in: [%f %f %f %f %f %f]\n", xform.a, xform.b, xform.c, xform.d, xform.tx, xform.ty);
|
fprintf (stderr, " xform in: [%f %f %f %f %f %f]\n", xform.a, xform.b, xform.c, xform.d, xform.tx, xform.ty);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ([self isUsingOpenGL]) {
|
|
||||||
// We usually don't get here for Gecko-initiated repaints. Instead, those
|
|
||||||
// eventually call drawUsingOpenGL, and don't go through drawRect.
|
|
||||||
// Paints that come through here are triggered by something that Cocoa
|
|
||||||
// controls, for example by window resizing or window focus changes.
|
|
||||||
|
|
||||||
// Since our window is usually declared as opaque, the window's pixel
|
|
||||||
// buffer may now contain garbage which we need to prevent from reaching
|
|
||||||
// the screen. The only place where garbage can show is in the bottom
|
|
||||||
// corners - the rest of the window is covered by our OpenGL surface.
|
|
||||||
// So we need to clear the pixel buffer contents in the corners.
|
|
||||||
[self maybeClearBottomCorners];
|
|
||||||
|
|
||||||
// Do GL composition and return.
|
|
||||||
[self drawUsingOpenGL];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PROFILER_LABEL("widget", "ChildView::drawRect");
|
|
||||||
|
|
||||||
nsIntRegion region;
|
nsIntRegion region;
|
||||||
nsIntRect boundingRect = mGeckoChild->CocoaPointsToDevPixels(aRect);
|
nsIntRect boundingRect = mGeckoChild->CocoaPointsToDevPixels(aRect);
|
||||||
const NSRect *rects;
|
const NSRect *rects;
|
||||||
NSInteger count, i;
|
NSInteger count, i;
|
||||||
[[NSView focusView] getRectsBeingDrawn:&rects count:&count];
|
[[NSView focusView] getRectsBeingDrawn:&rects count:&count];
|
||||||
|
|
||||||
|
CGContextClipToRects(aContext, (CGRect*)rects, count);
|
||||||
|
|
||||||
if (count < MAX_RECTS_IN_REGION) {
|
if (count < MAX_RECTS_IN_REGION) {
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
// Add the rect to the region.
|
// Add the rect to the region.
|
||||||
@ -2760,26 +3005,53 @@ NSEvent* gLastDragMouseDownEvent = nil;
|
|||||||
region = boundingRect;
|
region = boundingRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Cairo objects.
|
if ([self isUsingOpenGL]) {
|
||||||
|
// For Gecko-initiated repaints in OpenGL mode, drawUsingOpenGL is
|
||||||
|
// directly called from a delayed perform callback - without going through
|
||||||
|
// drawRect.
|
||||||
|
// Paints that come through here are triggered by something that Cocoa
|
||||||
|
// controls, for example by window resizing or window focus changes.
|
||||||
|
|
||||||
|
// Since this view is usually declared as opaque, the window's pixel
|
||||||
|
// buffer may now contain garbage which we need to prevent from reaching
|
||||||
|
// the screen. The only place where garbage can show is in the window
|
||||||
|
// corners - the rest of the window is covered by opaque content in our
|
||||||
|
// OpenGL surface.
|
||||||
|
// So we need to clear the pixel buffer contents in the corners.
|
||||||
|
[self clearCorners];
|
||||||
|
|
||||||
|
// When our view covers the titlebar, we need to repaint the titlebar
|
||||||
|
// texture buffer when, for example, the window buttons are hovered.
|
||||||
|
// So we notify our nsChildView about any areas needing repainting.
|
||||||
|
mGeckoChild->NotifyDirtyRegion(region);
|
||||||
|
|
||||||
|
// Do GL composition and return.
|
||||||
|
[self drawUsingOpenGL];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PROFILER_LABEL("widget", "ChildView::drawRect");
|
||||||
|
|
||||||
// The CGContext that drawRect supplies us with comes with a transform that
|
// The CGContext that drawRect supplies us with comes with a transform that
|
||||||
// scales one user space unit to one Cocoa point, which can consist of
|
// scales one user space unit to one Cocoa point, which can consist of
|
||||||
// multiple dev pixels. But Gecko expects its supplied context to be scaled
|
// multiple dev pixels. But Gecko expects its supplied context to be scaled
|
||||||
// to device pixels, so we need to reverse the scaling.
|
// to device pixels, so we need to reverse the scaling.
|
||||||
double scale = mGeckoChild->BackingScaleFactor();
|
double scale = mGeckoChild->BackingScaleFactor();
|
||||||
|
CGContextSaveGState(aContext);
|
||||||
CGContextScaleCTM(aContext, 1.0 / scale, 1.0 / scale);
|
CGContextScaleCTM(aContext, 1.0 / scale, 1.0 / scale);
|
||||||
|
|
||||||
NSSize viewSize = [self bounds].size;
|
NSSize viewSize = [self bounds].size;
|
||||||
nsIntSize backingSize(viewSize.width * scale, viewSize.height * scale);
|
nsIntSize backingSize(viewSize.width * scale, viewSize.height * scale);
|
||||||
|
|
||||||
|
CGContextSaveGState(aContext);
|
||||||
|
|
||||||
|
// Create Cairo objects.
|
||||||
nsRefPtr<gfxQuartzSurface> targetSurface =
|
nsRefPtr<gfxQuartzSurface> targetSurface =
|
||||||
new gfxQuartzSurface(aContext, backingSize);
|
new gfxQuartzSurface(aContext, backingSize);
|
||||||
targetSurface->SetAllowUseAsSource(false);
|
targetSurface->SetAllowUseAsSource(false);
|
||||||
|
|
||||||
nsRefPtr<gfxContext> targetContext = new gfxContext(targetSurface);
|
nsRefPtr<gfxContext> targetContext = new gfxContext(targetSurface);
|
||||||
|
|
||||||
gfxContextMatrixAutoSaveRestore save(targetContext);
|
|
||||||
|
|
||||||
// Set up the clip region.
|
// Set up the clip region.
|
||||||
nsIntRegionRectIterator iter(region);
|
nsIntRegionRectIterator iter(region);
|
||||||
targetContext->NewPath();
|
targetContext->NewPath();
|
||||||
@ -2806,6 +3078,15 @@ NSEvent* gLastDragMouseDownEvent = nil;
|
|||||||
painted = mGeckoChild->PaintWindow(region);
|
painted = mGeckoChild->PaintWindow(region);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
targetContext = nullptr;
|
||||||
|
targetSurface = nullptr;
|
||||||
|
|
||||||
|
CGContextRestoreGState(aContext);
|
||||||
|
|
||||||
|
// Undo the scale transform so that from now on the context is in
|
||||||
|
// CocoaPoints again.
|
||||||
|
CGContextRestoreGState(aContext);
|
||||||
|
|
||||||
if (!painted && [self isOpaque]) {
|
if (!painted && [self isOpaque]) {
|
||||||
// Gecko refused to draw, but we've claimed to be opaque, so we have to
|
// Gecko refused to draw, but we've claimed to be opaque, so we have to
|
||||||
// draw something--fill with white.
|
// draw something--fill with white.
|
||||||
@ -2813,9 +3094,10 @@ NSEvent* gLastDragMouseDownEvent = nil;
|
|||||||
CGContextFillRect(aContext, NSRectToCGRect(aRect));
|
CGContextFillRect(aContext, NSRectToCGRect(aRect));
|
||||||
}
|
}
|
||||||
|
|
||||||
// note that the cairo surface *MUST* be destroyed at this point,
|
if ([self isCoveringTitlebar]) {
|
||||||
// or bad things will happen (since we can't keep the cgContext around
|
[self drawTitlebarHighlight];
|
||||||
// beyond this drawRect message handler)
|
[self maskTopCornersInContext:aContext];
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_UPDATE
|
#ifdef DEBUG_UPDATE
|
||||||
fprintf (stderr, "---- update done ----\n");
|
fprintf (stderr, "---- update done ----\n");
|
||||||
@ -2900,39 +3182,92 @@ NSEvent* gLastDragMouseDownEvent = nil;
|
|||||||
[[self window] bottomCornerRounded];
|
[[self window] bottomCornerRounded];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGFloat)bottomCornerRadius
|
- (CGFloat)cornerRadius
|
||||||
{
|
{
|
||||||
if (![self hasRoundedBottomCorners])
|
NSView* frameView = [[[self window] contentView] superview];
|
||||||
return 0.0f;
|
if (!frameView || ![frameView respondsToSelector:@selector(roundedCornerRadius)])
|
||||||
NSView* borderView = [[[self window] contentView] superview];
|
|
||||||
if (!borderView || ![borderView respondsToSelector:@selector(roundedCornerRadius)])
|
|
||||||
return 4.0f;
|
return 4.0f;
|
||||||
return [borderView roundedCornerRadius];
|
return [frameView roundedCornerRadius];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accelerated windows have two NSSurfaces:
|
// Accelerated windows have two NSSurfaces:
|
||||||
// (1) The window's pixel buffer in the back and
|
// (1) The window's pixel buffer in the back and
|
||||||
// (2) the OpenGL view in the front.
|
// (2) the OpenGL view in the front.
|
||||||
// These two surfaces are composited by the window manager. Drawing with the
|
// These two surfaces are composited by the window manager. Drawing into the
|
||||||
// usual CGContext functions ends up in (1).
|
// CGContext which is provided by drawRect ends up in (1).
|
||||||
// When our window has rounded bottom corners, the OpenGL view has transparent
|
// When our window has rounded corners, the OpenGL view has transparent pixels
|
||||||
// pixels in the corners. In these places the contents of the window's pixel
|
// in the corners. In these places the contents of the window's pixel buffer
|
||||||
// buffer can show through. So we need to make sure that the pixel buffer is
|
// can show through. So we need to make sure that the pixel buffer is
|
||||||
// transparent in the corners so that no garbage reaches the screen.
|
// transparent in the corners so that no garbage reaches the screen.
|
||||||
// The contents of the pixel buffer in the rest of the window don't matter
|
// The contents of the pixel buffer in the rest of the window don't matter
|
||||||
// because they're covered by the OpenGL view.
|
// because they're covered by opaque pixels of the OpenGL context.
|
||||||
// Making the bottom corners transparent works even though our window is
|
// Making the corners transparent works even though our window is
|
||||||
// declared "opaque" (in the NSWindow's isOpaque method).
|
// declared "opaque" (in the NSWindow's isOpaque method).
|
||||||
- (void)maybeClearBottomCorners
|
- (void)clearCorners
|
||||||
{
|
{
|
||||||
if (![self hasRoundedBottomCorners])
|
CGFloat radius = [self cornerRadius];
|
||||||
return;
|
CGFloat w = [self bounds].size.width, h = [self bounds].size.height;
|
||||||
|
|
||||||
int radius = [self bottomCornerRadius];
|
|
||||||
int w = [self bounds].size.width, h = [self bounds].size.height;
|
|
||||||
[[NSColor clearColor] set];
|
[[NSColor clearColor] set];
|
||||||
NSRectFill(NSMakeRect(0, h - radius, radius, radius));
|
|
||||||
NSRectFill(NSMakeRect(w - radius, h - radius, radius, radius));
|
if ([self isCoveringTitlebar]) {
|
||||||
|
NSRectFill(NSMakeRect(0, 0, radius, radius));
|
||||||
|
NSRectFill(NSMakeRect(w - radius, 0, radius, radius));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([self hasRoundedBottomCorners]) {
|
||||||
|
NSRectFill(NSMakeRect(0, h - radius, radius, radius));
|
||||||
|
NSRectFill(NSMakeRect(w - radius, h - radius, radius, radius));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the analog of nsChildView::MaybeDrawRoundedCorners for CGContexts.
|
||||||
|
// We only need to mask the top corners here because Cocoa does the masking
|
||||||
|
// for the window's bottom corners automatically (starting with 10.7).
|
||||||
|
- (void)maskTopCornersInContext:(CGContextRef)aContext
|
||||||
|
{
|
||||||
|
CGFloat radius = [self cornerRadius];
|
||||||
|
int32_t devPixelCornerRadius = mGeckoChild->CocoaPointsToDevPixels(radius);
|
||||||
|
|
||||||
|
// First make sure that mTopLeftCornerMask is set up.
|
||||||
|
if (!mTopLeftCornerMask ||
|
||||||
|
int32_t(CGImageGetWidth(mTopLeftCornerMask)) != devPixelCornerRadius) {
|
||||||
|
CGImageRelease(mTopLeftCornerMask);
|
||||||
|
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
|
||||||
|
CGContextRef imgCtx = CGBitmapContextCreate(NULL,
|
||||||
|
devPixelCornerRadius,
|
||||||
|
devPixelCornerRadius,
|
||||||
|
8, devPixelCornerRadius * 4,
|
||||||
|
rgb, kCGImageAlphaPremultipliedFirst);
|
||||||
|
CGColorSpaceRelease(rgb);
|
||||||
|
DrawTopLeftCornerMask(imgCtx, devPixelCornerRadius);
|
||||||
|
mTopLeftCornerMask = CGBitmapContextCreateImage(imgCtx);
|
||||||
|
CGContextRelease(imgCtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// kCGBlendModeDestinationIn is the secret sauce which allows us to erase
|
||||||
|
// already painted pixels. It's defined as R = D * Sa: multiply all channels
|
||||||
|
// of the destination pixel with the alpha of the source pixel. In our case,
|
||||||
|
// the source is mTopLeftCornerMask.
|
||||||
|
CGContextSaveGState(aContext);
|
||||||
|
CGContextSetBlendMode(aContext, kCGBlendModeDestinationIn);
|
||||||
|
|
||||||
|
CGRect destRect = CGRectMake(0, 0, radius, radius);
|
||||||
|
|
||||||
|
// Erase the top left corner...
|
||||||
|
CGContextDrawImage(aContext, destRect, mTopLeftCornerMask);
|
||||||
|
|
||||||
|
// ... and the top right corner.
|
||||||
|
CGContextTranslateCTM(aContext, [self bounds].size.width, 0);
|
||||||
|
CGContextScaleCTM(aContext, -1, 1);
|
||||||
|
CGContextDrawImage(aContext, destRect, mTopLeftCornerMask);
|
||||||
|
|
||||||
|
CGContextRestoreGState(aContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drawTitlebarHighlight
|
||||||
|
{
|
||||||
|
DrawTitlebarHighlight([self bounds].size, [self cornerRadius],
|
||||||
|
mGeckoChild->DevPixelsToCocoaPoints(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)releaseWidgets:(NSArray*)aWidgetArray
|
- (void)releaseWidgets:(NSArray*)aWidgetArray
|
||||||
|
@ -97,6 +97,8 @@ typedef struct _nsCocoaWindowList {
|
|||||||
|
|
||||||
- (ChildView*)mainChildView;
|
- (ChildView*)mainChildView;
|
||||||
|
|
||||||
|
- (NSArray*)titlebarControls;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface NSWindow (Undocumented)
|
@interface NSWindow (Undocumented)
|
||||||
|
@ -2716,6 +2716,15 @@ static const NSString* kStateShowsToolbarButton = @"showsToolbarButton";
|
|||||||
[frameView addSubview:aView positioned:NSWindowBelow relativeTo:nil];
|
[frameView addSubview:aView positioned:NSWindowBelow relativeTo:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSArray*)titlebarControls
|
||||||
|
{
|
||||||
|
// Return all subviews of the frameView which are not the content view.
|
||||||
|
NSView* frameView = [[self contentView] superview];
|
||||||
|
NSMutableArray* array = [[[frameView subviews] mutableCopy] autorelease];
|
||||||
|
[array removeObject:[self contentView]];
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)respondsToSelector:(SEL)aSelector
|
- (BOOL)respondsToSelector:(SEL)aSelector
|
||||||
{
|
{
|
||||||
// Claim the window doesn't respond to this so that the system
|
// Claim the window doesn't respond to this so that the system
|
||||||
|
Loading…
Reference in New Issue
Block a user