Bug 1777562 [wpt PR 34663] - [FedCM] Rename FederatedCredential to IdentityCredential...
[gecko.git] / widget / uikit / nsWindow.mm
blob663ebc80bf1e06d0bba6c7cdc5b1edead62f6821
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #import <UIKit/UIEvent.h>
7 #import <UIKit/UIGraphics.h>
8 #import <UIKit/UIInterface.h>
9 #import <UIKit/UIScreen.h>
10 #import <UIKit/UITapGestureRecognizer.h>
11 #import <UIKit/UITouch.h>
12 #import <UIKit/UIView.h>
13 #import <UIKit/UIViewController.h>
14 #import <UIKit/UIWindow.h>
15 #import <QuartzCore/QuartzCore.h>
17 #include <algorithm>
19 #include "nsWindow.h"
20 #include "nsScreenManager.h"
21 #include "nsAppShell.h"
23 #include "nsWidgetsCID.h"
24 #include "nsGfxCIID.h"
26 #include "gfxQuartzSurface.h"
27 #include "gfxUtils.h"
28 #include "gfxImageSurface.h"
29 #include "gfxContext.h"
30 #include "nsRegion.h"
31 #include "Layers.h"
32 #include "nsTArray.h"
34 #include "mozilla/BasicEvents.h"
35 #include "mozilla/ProfilerLabels.h"
36 #include "mozilla/TouchEvents.h"
37 #include "mozilla/Unused.h"
38 #include "mozilla/dom/MouseEventBinding.h"
40 using namespace mozilla;
41 using namespace mozilla::dom;
42 using namespace mozilla::layers;
44 #define ALOG(args...)    \
45   fprintf(stderr, args); \
46   fprintf(stderr, "\n")
48 static LayoutDeviceIntPoint UIKitPointsToDevPixels(CGPoint aPoint, CGFloat aBackingScale) {
49   return LayoutDeviceIntPoint(NSToIntRound(aPoint.x * aBackingScale),
50                               NSToIntRound(aPoint.y * aBackingScale));
53 static CGRect DevPixelsToUIKitPoints(const LayoutDeviceIntRect& aRect, CGFloat aBackingScale) {
54   return CGRectMake((CGFloat)aRect.x / aBackingScale, (CGFloat)aRect.y / aBackingScale,
55                     (CGFloat)aRect.width / aBackingScale, (CGFloat)aRect.height / aBackingScale);
58 // Used to retain a Cocoa object for the remainder of a method's execution.
59 class nsAutoRetainUIKitObject {
60  public:
61   nsAutoRetainUIKitObject(id anObject) { mObject = [anObject retain]; }
62   ~nsAutoRetainUIKitObject() { [mObject release]; }
64  private:
65   id mObject;  // [STRONG]
68 @interface ChildView : UIView {
69  @public
70   nsWindow* mGeckoChild;  // weak ref
71   BOOL mWaitingForPaint;
72   CFMutableDictionaryRef mTouches;
73   int mNextTouchID;
75 // sets up our view, attaching it to its owning gecko view
76 - (id)initWithFrame:(CGRect)inFrame geckoChild:(nsWindow*)inChild;
77 // Our Gecko child was Destroy()ed
78 - (void)widgetDestroyed;
79 // Tear down this ChildView
80 - (void)delayedTearDown;
81 - (void)sendMouseEvent:(EventMessage)aType
82                  point:(LayoutDeviceIntPoint)aPoint
83                 widget:(nsWindow*)aWindow;
84 - (void)handleTap:(UITapGestureRecognizer*)sender;
85 - (BOOL)isUsingMainThreadOpenGL;
86 - (void)drawUsingOpenGL;
87 - (void)drawUsingOpenGLCallback;
88 - (void)sendTouchEvent:(EventMessage)aType touches:(NSSet*)aTouches widget:(nsWindow*)aWindow;
89 // Event handling (UIResponder)
90 - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event;
91 - (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event;
92 - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event;
93 - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event;
94 @end
96 @implementation ChildView
97 + (Class)layerClass {
98   return [CAEAGLLayer class];
101 - (id)initWithFrame:(CGRect)inFrame geckoChild:(nsWindow*)inChild {
102   self.multipleTouchEnabled = YES;
103   if ((self = [super initWithFrame:inFrame])) {
104     mGeckoChild = inChild;
105   }
106   ALOG("[ChildView[%p] initWithFrame:] (mGeckoChild = %p)", (void*)self, (void*)mGeckoChild);
107   self.opaque = YES;
108   self.alpha = 1.0;
110   UITapGestureRecognizer* tapRecognizer =
111       [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
112   tapRecognizer.numberOfTapsRequired = 1;
113   [self addGestureRecognizer:tapRecognizer];
115   mTouches = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr);
116   mNextTouchID = 0;
117   return self;
120 - (void)widgetDestroyed {
121   mGeckoChild = nullptr;
122   CFRelease(mTouches);
125 - (void)delayedTearDown {
126   [self removeFromSuperview];
127   [self release];
130 - (void)sendMouseEvent:(EventMessage)aType
131                  point:(LayoutDeviceIntPoint)aPoint
132                 widget:(nsWindow*)aWindow {
133   WidgetMouseEvent event(true, aType, aWindow, WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
135   event.mRefPoint = aPoint;
136   event.mClickCount = 1;
137   event.button = MouseButton::ePrimary;
138   event.mTime = PR_IntervalNow();
139   event.inputSource = MouseEvent_Binding::MOZ_SOURCE_UNKNOWN;
141   nsEventStatus status;
142   aWindow->DispatchEvent(&event, status);
145 - (void)handleTap:(UITapGestureRecognizer*)sender {
146   if (sender.state == UIGestureRecognizerStateEnded) {
147     ALOG("[ChildView[%p] handleTap]", self);
148     LayoutDeviceIntPoint lp =
149         UIKitPointsToDevPixels([sender locationInView:self], [self contentScaleFactor]);
150     [self sendMouseEvent:eMouseMove point:lp widget:mGeckoChild];
151     [self sendMouseEvent:eMouseDown point:lp widget:mGeckoChild];
152     [self sendMouseEvent:eMouseUp point:lp widget:mGeckoChild];
153   }
156 - (void)sendTouchEvent:(EventMessage)aType touches:(NSSet*)aTouches widget:(nsWindow*)aWindow {
157   WidgetTouchEvent event(true, aType, aWindow);
158   // XXX: I think nativeEvent.timestamp * 1000 is probably usable here but
159   // I don't care that much right now.
160   event.mTime = PR_IntervalNow();
161   event.mTouches.SetCapacity(aTouches.count);
162   for (UITouch* touch in aTouches) {
163     LayoutDeviceIntPoint loc =
164         UIKitPointsToDevPixels([touch locationInView:self], [self contentScaleFactor]);
165     LayoutDeviceIntPoint radius = UIKitPointsToDevPixels([touch majorRadius], [touch majorRadius]);
166     void* value;
167     if (!CFDictionaryGetValueIfPresent(mTouches, touch, (const void**)&value)) {
168       // This shouldn't happen.
169       NS_ASSERTION(false, "Got a touch that we didn't know about");
170       continue;
171     }
172     int id = reinterpret_cast<int>(value);
173     RefPtr<Touch> t = new Touch(id, loc, radius, 0.0f, 1.0f);
174     event.mRefPoint = loc;
175     event.mTouches.AppendElement(t);
176   }
177   aWindow->DispatchInputEvent(&event);
180 - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
181   ALOG("[ChildView[%p] touchesBegan", self);
182   if (!mGeckoChild) return;
184   for (UITouch* touch : touches) {
185     CFDictionaryAddValue(mTouches, touch, (void*)mNextTouchID);
186     mNextTouchID++;
187   }
188   [self sendTouchEvent:eTouchStart touches:[event allTouches] widget:mGeckoChild];
191 - (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
192   ALOG("[ChildView[%p] touchesCancelled", self);
193   [self sendTouchEvent:eTouchCancel touches:touches widget:mGeckoChild];
194   for (UITouch* touch : touches) {
195     CFDictionaryRemoveValue(mTouches, touch);
196   }
197   if (CFDictionaryGetCount(mTouches) == 0) {
198     mNextTouchID = 0;
199   }
202 - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
203   ALOG("[ChildView[%p] touchesEnded", self);
204   if (!mGeckoChild) return;
206   [self sendTouchEvent:eTouchEnd touches:touches widget:mGeckoChild];
207   for (UITouch* touch : touches) {
208     CFDictionaryRemoveValue(mTouches, touch);
209   }
210   if (CFDictionaryGetCount(mTouches) == 0) {
211     mNextTouchID = 0;
212   }
215 - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
216   ALOG("[ChildView[%p] touchesMoved", self);
217   if (!mGeckoChild) return;
219   [self sendTouchEvent:eTouchMove touches:[event allTouches] widget:mGeckoChild];
222 - (void)setNeedsDisplayInRect:(CGRect)aRect {
223   if ([self isUsingMainThreadOpenGL]) {
224     // Draw without calling drawRect. This prevent us from
225     // needing to access the normal window buffer surface unnecessarily, so we
226     // waste less time synchronizing the two surfaces.
227     if (!mWaitingForPaint) {
228       mWaitingForPaint = YES;
229       // Use NSRunLoopCommonModes instead of the default NSDefaultRunLoopMode
230       // so that the timer also fires while a native menu is open.
231       [self performSelector:@selector(drawUsingOpenGLCallback)
232                  withObject:nil
233                  afterDelay:0
234                     inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
235     }
236   }
239 - (BOOL)isUsingMainThreadOpenGL {
240   if (!mGeckoChild || ![self window]) return NO;
242   return NO;
245 - (void)drawUsingOpenGL {
246   ALOG("drawUsingOpenGL");
247   AUTO_PROFILER_LABEL("ChildView::drawUsingOpenGL", OTHER);
249   if (!mGeckoChild->IsVisible()) return;
251   mWaitingForPaint = NO;
253   LayoutDeviceIntRect geckoBounds = mGeckoChild->GetBounds();
254   LayoutDeviceIntRegion region(geckoBounds);
256   mGeckoChild->PaintWindow(region);
259 // Called asynchronously after setNeedsDisplay in order to avoid entering the
260 // normal drawing machinery.
261 - (void)drawUsingOpenGLCallback {
262   if (mWaitingForPaint) {
263     [self drawUsingOpenGL];
264   }
267 // The display system has told us that a portion of our view is dirty. Tell
268 // gecko to paint it
269 - (void)drawRect:(CGRect)aRect {
270   CGContextRef cgContext = UIGraphicsGetCurrentContext();
271   [self drawRect:aRect inContext:cgContext];
274 - (void)drawRect:(CGRect)aRect inContext:(CGContextRef)aContext {
275 #ifdef DEBUG_UPDATE
276   LayoutDeviceIntRect geckoBounds = mGeckoChild->GetBounds();
278   fprintf(stderr, "---- Update[%p][%p] [%f %f %f %f] cgc: %p\n  gecko bounds: [%d %d %d %d]\n",
279           self, mGeckoChild, aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height,
280           aContext, geckoBounds.x, geckoBounds.y, geckoBounds.width, geckoBounds.height);
282   CGAffineTransform xform = CGContextGetCTM(aContext);
283   fprintf(stderr, "  xform in: [%f %f %f %f %f %f]\n", xform.a, xform.b, xform.c, xform.d, xform.tx,
284           xform.ty);
285 #endif
287   if (true) {
288     // For Gecko-initiated repaints in OpenGL mode, drawUsingOpenGL is
289     // directly called from a delayed perform callback - without going through
290     // drawRect.
291     // Paints that come through here are triggered by something that Cocoa
292     // controls, for example by window resizing or window focus changes.
294     // Do GL composition and return.
295     [self drawUsingOpenGL];
296     return;
297   }
298   AUTO_PROFILER_LABEL("ChildView::drawRect", OTHER);
300   // The CGContext that drawRect supplies us with comes with a transform that
301   // scales one user space unit to one Cocoa point, which can consist of
302   // multiple dev pixels. But Gecko expects its supplied context to be scaled
303   // to device pixels, so we need to reverse the scaling.
304   double scale = mGeckoChild->BackingScaleFactor();
305   CGContextSaveGState(aContext);
306   CGContextScaleCTM(aContext, 1.0 / scale, 1.0 / scale);
308   CGSize viewSize = [self bounds].size;
309   gfx::IntSize backingSize(viewSize.width * scale, viewSize.height * scale);
311   CGContextSaveGState(aContext);
313   LayoutDeviceIntRegion region = LayoutDeviceIntRect(
314       NSToIntRound(aRect.origin.x * scale), NSToIntRound(aRect.origin.y * scale),
315       NSToIntRound(aRect.size.width * scale), NSToIntRound(aRect.size.height * scale));
317   // Create Cairo objects.
318   RefPtr<gfxQuartzSurface> targetSurface;
320   RefPtr<gfxContext> targetContext;
321   if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(gfx::BackendType::CAIRO)) {
322     // This is dead code unless you mess with prefs, but keep it around for
323     // debugging.
324     targetSurface = new gfxQuartzSurface(aContext, backingSize);
325     targetSurface->SetAllowUseAsSource(false);
326     RefPtr<gfx::DrawTarget> dt =
327         gfxPlatform::CreateDrawTargetForSurface(targetSurface, backingSize);
328     if (!dt || !dt->IsValid()) {
329       gfxDevCrash(mozilla::gfx::LogReason::InvalidContext)
330           << "Window context problem 2 " << backingSize;
331       return;
332     }
333     targetContext = gfxContext::CreateOrNull(dt);
334   } else {
335     MOZ_ASSERT_UNREACHABLE("COREGRAPHICS is the only supported backend");
336   }
337   MOZ_ASSERT(targetContext);  // already checked for valid draw targets above
339   // Set up the clip region.
340   targetContext->NewPath();
341   for (auto iter = region.RectIter(); !iter.Done(); iter.Next()) {
342     const LayoutDeviceIntRect& r = iter.Get();
343     targetContext->Rectangle(gfxRect(r.x, r.y, r.width, r.height));
344   }
345   targetContext->Clip();
347   // nsAutoRetainCocoaObject kungFuDeathGrip(self);
348   bool painted = false;
349   targetContext = nullptr;
350   targetSurface = nullptr;
352   CGContextRestoreGState(aContext);
354   // Undo the scale transform so that from now on the context is in
355   // CocoaPoints again.
356   CGContextRestoreGState(aContext);
357   if (!painted && [self isOpaque]) {
358     // Gecko refused to draw, but we've claimed to be opaque, so we have to
359     // draw something--fill with white.
360     CGContextSetRGBFillColor(aContext, 1, 1, 1, 1);
361     CGContextFillRect(aContext, aRect);
362   }
364 #ifdef DEBUG_UPDATE
365   fprintf(stderr, "---- update done ----\n");
367 #  if 0
368   CGContextSetRGBStrokeColor (aContext,
369                             ((((unsigned long)self) & 0xff)) / 255.0,
370                             ((((unsigned long)self) & 0xff00) >> 8) / 255.0,
371                             ((((unsigned long)self) & 0xff0000) >> 16) / 255.0,
372                             0.5);
373 #  endif
374   CGContextSetRGBStrokeColor(aContext, 1, 0, 0, 0.8);
375   CGContextSetLineWidth(aContext, 4.0);
376   CGContextStrokeRect(aContext, aRect);
377 #endif
379 @end
381 nsWindow::nsWindow()
382     : mNativeView(nullptr), mVisible(false), mSizeMode(nsSizeMode_Normal), mParent(nullptr) {}
384 nsWindow::~nsWindow() {
385   [mNativeView widgetDestroyed];  // Safe if mNativeView is nil.
386   TearDownView();                 // Safe if called twice.
389 void nsWindow::TearDownView() {
390   if (!mNativeView) return;
392   [mNativeView performSelectorOnMainThread:@selector(delayedTearDown)
393                                 withObject:nil
394                              waitUntilDone:false];
395   mNativeView = nil;
398 bool nsWindow::IsTopLevel() {
399   return mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog ||
400          mWindowType == eWindowType_invisible;
404 // nsIWidget
407 nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
408                           const LayoutDeviceIntRect& aRect, nsWidgetInitData* aInitData) {
409   ALOG("nsWindow[%p]::Create %p/%p [%d %d %d %d]", (void*)this, (void*)aParent,
410        (void*)aNativeParent, aRect.x, aRect.y, aRect.width, aRect.height);
411   nsWindow* parent = (nsWindow*)aParent;
412   ChildView* nativeParent = (ChildView*)aNativeParent;
414   if (parent == nullptr && nativeParent) parent = nativeParent->mGeckoChild;
415   if (parent && nativeParent == nullptr) nativeParent = parent->mNativeView;
417   // for toplevel windows, bounds are fixed to full screen size
418   if (parent == nullptr) {
419     if (nsAppShell::gWindow == nil) {
420       mBounds = UIKitScreenManager::GetBounds();
421     } else {
422       CGRect cgRect = [nsAppShell::gWindow bounds];
423       mBounds.x = cgRect.origin.x;
424       mBounds.y = cgRect.origin.y;
425       mBounds.width = cgRect.size.width;
426       mBounds.height = cgRect.size.height;
427     }
428   } else {
429     mBounds = aRect;
430   }
432   ALOG("nsWindow[%p]::Create bounds: %d %d %d %d", (void*)this, mBounds.x, mBounds.y, mBounds.width,
433        mBounds.height);
435   // Set defaults which can be overriden from aInitData in BaseCreate
436   mWindowType = eWindowType_toplevel;
437   mBorderStyle = eBorderStyle_default;
439   Inherited::BaseCreate(aParent, aInitData);
441   NS_ASSERTION(IsTopLevel() || parent, "non top level window doesn't have a parent!");
443   mNativeView =
444       [[ChildView alloc] initWithFrame:DevPixelsToUIKitPoints(mBounds, BackingScaleFactor())
445                             geckoChild:this];
446   mNativeView.hidden = YES;
448   if (parent) {
449     parent->mChildren.AppendElement(this);
450     mParent = parent;
451   }
453   if (nativeParent) {
454     [nativeParent addSubview:mNativeView];
455   } else if (nsAppShell::gWindow) {
456     [nsAppShell::gWindow.rootViewController.view addSubview:mNativeView];
457   } else {
458     [nsAppShell::gTopLevelViews addObject:mNativeView];
459   }
461   return NS_OK;
464 void nsWindow::Destroy() {
465   for (uint32_t i = 0; i < mChildren.Length(); ++i) {
466     // why do we still have children?
467     mChildren[i]->SetParent(nullptr);
468   }
470   if (mParent) mParent->mChildren.RemoveElement(this);
472   [mNativeView widgetDestroyed];
474   nsBaseWidget::Destroy();
476   // ReportDestroyEvent();
478   TearDownView();
480   nsBaseWidget::OnDestroy();
482   return NS_OK;
485 void nsWindow::Show(bool aState) {
486   if (aState != mVisible) {
487     mNativeView.hidden = aState ? NO : YES;
488     if (aState) {
489       UIView* parentView =
490           mParent ? mParent->mNativeView : nsAppShell::gWindow.rootViewController.view;
491       [parentView bringSubviewToFront:mNativeView];
492       [mNativeView setNeedsDisplay];
493     }
494     mVisible = aState;
495   }
498 void nsWindow::Move(double aX, double aY) {
499   if (!mNativeView || (mBounds.x == aX && mBounds.y == aY)) return;
501   // XXX: handle this
502   // The point we have is in Gecko coordinates (origin top-left). Convert
503   // it to Cocoa ones (origin bottom-left).
504   mBounds.x = aX;
505   mBounds.y = aY;
507   mNativeView.frame = DevPixelsToUIKitPoints(mBounds, BackingScaleFactor());
509   if (mVisible) [mNativeView setNeedsDisplay];
511   ReportMoveEvent();
514 void nsWindow::Resize(double aX, double aY, double aWidth, double aHeight, bool aRepaint) {
515   BOOL isMoving = (mBounds.x != aX || mBounds.y != aY);
516   BOOL isResizing = (mBounds.width != aWidth || mBounds.height != aHeight);
517   if (!mNativeView || (!isMoving && !isResizing)) return;
519   if (isMoving) {
520     mBounds.x = aX;
521     mBounds.y = aY;
522   }
523   if (isResizing) {
524     mBounds.width = aWidth;
525     mBounds.height = aHeight;
526   }
528   [mNativeView setFrame:DevPixelsToUIKitPoints(mBounds, BackingScaleFactor())];
530   if (mVisible && aRepaint) [mNativeView setNeedsDisplay];
532   if (isMoving) ReportMoveEvent();
534   if (isResizing) ReportSizeEvent();
537 void nsWindow::Resize(double aWidth, double aHeight, bool aRepaint) {
538   if (!mNativeView || (mBounds.width == aWidth && mBounds.height == aHeight)) return;
540   mBounds.width = aWidth;
541   mBounds.height = aHeight;
543   [mNativeView setFrame:DevPixelsToUIKitPoints(mBounds, BackingScaleFactor())];
545   if (mVisible && aRepaint) [mNativeView setNeedsDisplay];
547   ReportSizeEvent();
550 void nsWindow::SetSizeMode(nsSizeMode aMode) {
551   if (aMode == static_cast<int32_t>(mSizeMode)) {
552     return;
553   }
555   mSizeMode = static_cast<nsSizeMode>(aMode);
556   if (aMode == nsSizeMode_Maximized || aMode == nsSizeMode_Fullscreen) {
557     // Resize to fill screen
558     nsBaseWidget::InfallibleMakeFullScreen(true);
559   }
560   ReportSizeModeEvent(aMode);
563 void nsWindow::Invalidate(const LayoutDeviceIntRect& aRect) {
564   if (!mNativeView || !mVisible) return;
566   MOZ_RELEASE_ASSERT(GetLayerManager()->GetBackendType() != LayersBackend::LAYERS_WR,
567                      "Shouldn't need to invalidate with accelerated OMTC layers!");
569   [mNativeView setNeedsLayout];
570   [mNativeView setNeedsDisplayInRect:DevPixelsToUIKitPoints(mBounds, BackingScaleFactor())];
573 void nsWindow::SetFocus(Raise) {
574   [[mNativeView window] makeKeyWindow];
575   [mNativeView becomeFirstResponder];
578 void nsWindow::WillPaintWindow() {
579   if (mWidgetListener) {
580     mWidgetListener->WillPaintWindow(this);
581   }
584 bool nsWindow::PaintWindow(LayoutDeviceIntRegion aRegion) {
585   if (!mWidgetListener) return false;
587   bool returnValue = false;
588   returnValue = mWidgetListener->PaintWindow(this, aRegion);
590   if (mWidgetListener) {
591     mWidgetListener->DidPaintWindow();
592   }
594   return returnValue;
597 void nsWindow::ReportMoveEvent() { NotifyWindowMoved(mBounds.x, mBounds.y); }
599 void nsWindow::ReportSizeModeEvent(nsSizeMode aMode) {
600   if (mWidgetListener) {
601     // This is terrible.
602     nsSizeMode theMode;
603     switch (aMode) {
604       case nsSizeMode_Maximized:
605         theMode = nsSizeMode_Maximized;
606         break;
607       case nsSizeMode_Fullscreen:
608         theMode = nsSizeMode_Fullscreen;
609         break;
610       default:
611         return;
612     }
613     mWidgetListener->SizeModeChanged(theMode);
614   }
617 void nsWindow::ReportSizeEvent() {
618   if (mWidgetListener) {
619     LayoutDeviceIntRect innerBounds = GetClientBounds();
620     mWidgetListener->WindowResized(this, innerBounds.width, innerBounds.height);
621   }
624 LayoutDeviceIntRect nsWindow::GetScreenBounds() {
625   return LayoutDeviceIntRect(WidgetToScreenOffset(), mBounds.Size());
628 LayoutDeviceIntPoint nsWindow::WidgetToScreenOffset() {
629   LayoutDeviceIntPoint offset(0, 0);
630   if (mParent) {
631     offset = mParent->WidgetToScreenOffset();
632   }
634   CGPoint temp = [mNativeView convertPoint:temp toView:nil];
636   if (!mParent && nsAppShell::gWindow) {
637     // convert to screen coords
638     temp = [nsAppShell::gWindow convertPoint:temp toWindow:nil];
639   }
641   offset.x += temp.x;
642   offset.y += temp.y;
644   return offset;
647 nsresult nsWindow::DispatchEvent(mozilla::WidgetGUIEvent* aEvent, nsEventStatus& aStatus) {
648   aStatus = nsEventStatus_eIgnore;
649   nsCOMPtr<nsIWidget> kungFuDeathGrip(aEvent->mWidget);
651   if (mWidgetListener) aStatus = mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
653   return NS_OK;
656 void nsWindow::SetInputContext(const InputContext& aContext, const InputContextAction& aAction) {
657   // TODO: actually show VKB
658   mInputContext = aContext;
661 mozilla::widget::InputContext nsWindow::GetInputContext() { return mInputContext; }
663 void nsWindow::SetBackgroundColor(const nscolor& aColor) {
664   mNativeView.backgroundColor = [UIColor colorWithRed:NS_GET_R(aColor)
665                                                 green:NS_GET_G(aColor)
666                                                  blue:NS_GET_B(aColor)
667                                                 alpha:NS_GET_A(aColor)];
670 void* nsWindow::GetNativeData(uint32_t aDataType) {
671   void* retVal = nullptr;
673   switch (aDataType) {
674     case NS_NATIVE_WIDGET:
675     case NS_NATIVE_DISPLAY:
676       retVal = (void*)mNativeView;
677       break;
679     case NS_NATIVE_WINDOW:
680       retVal = [mNativeView window];
681       break;
683     case NS_NATIVE_GRAPHIC:
684       NS_ERROR("Requesting NS_NATIVE_GRAPHIC on a UIKit child view!");
685       break;
687     case NS_NATIVE_OFFSETX:
688       retVal = 0;
689       break;
691     case NS_NATIVE_OFFSETY:
692       retVal = 0;
693       break;
695     case NS_RAW_NATIVE_IME_CONTEXT:
696       retVal = GetPseudoIMEContext();
697       if (retVal) {
698         break;
699       }
700       retVal = NS_ONLY_ONE_NATIVE_IME_CONTEXT;
701       break;
702   }
704   return retVal;
707 CGFloat nsWindow::BackingScaleFactor() {
708   if (mNativeView) {
709     return [mNativeView contentScaleFactor];
710   }
711   return [UIScreen mainScreen].scale;
714 int32_t nsWindow::RoundsWidgetCoordinatesTo() {
715   if (BackingScaleFactor() == 2.0) {
716     return 2;
717   }
718   return 1;
721 already_AddRefed<nsIWidget> nsIWidget::CreateTopLevelWindow() {
722   nsCOMPtr<nsIWidget> window = new nsWindow();
723   return window.forget();
726 already_AddRefed<nsIWidget> nsIWidget::CreateChildWindow() {
727   nsCOMPtr<nsIWidget> window = new nsWindow();
728   return window.forget();