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>
20 #include "nsScreenManager.h"
21 #include "nsAppShell.h"
23 #include "nsWidgetsCID.h"
24 #include "nsGfxCIID.h"
26 #include "gfxQuartzSurface.h"
28 #include "gfxImageSurface.h"
29 #include "gfxContext.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); \
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 {
61 nsAutoRetainUIKitObject(id anObject) { mObject = [anObject retain]; }
62 ~nsAutoRetainUIKitObject() { [mObject release]; }
65 id mObject; // [STRONG]
68 @interface ChildView : UIView {
70 nsWindow* mGeckoChild; // weak ref
71 BOOL mWaitingForPaint;
72 CFMutableDictionaryRef mTouches;
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;
96 @implementation ChildView
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;
106 ALOG("[ChildView[%p] initWithFrame:] (mGeckoChild = %p)", (void*)self, (void*)mGeckoChild);
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);
120 - (void)widgetDestroyed {
121 mGeckoChild = nullptr;
125 - (void)delayedTearDown {
126 [self removeFromSuperview];
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];
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]);
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");
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);
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);
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);
197 if (CFDictionaryGetCount(mTouches) == 0) {
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);
210 if (CFDictionaryGetCount(mTouches) == 0) {
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)
234 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
239 - (BOOL)isUsingMainThreadOpenGL {
240 if (!mGeckoChild || ![self window]) 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];
267 // The display system has told us that a portion of our view is dirty. Tell
269 - (void)drawRect:(CGRect)aRect {
270 CGContextRef cgContext = UIGraphicsGetCurrentContext();
271 [self drawRect:aRect inContext:cgContext];
274 - (void)drawRect:(CGRect)aRect inContext:(CGContextRef)aContext {
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,
288 // For Gecko-initiated repaints in OpenGL mode, drawUsingOpenGL is
289 // directly called from a delayed perform callback - without going through
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];
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
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;
333 targetContext = gfxContext::CreateOrNull(dt);
335 MOZ_ASSERT_UNREACHABLE("COREGRAPHICS is the only supported backend");
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));
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);
365 fprintf(stderr, "---- update done ----\n");
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,
374 CGContextSetRGBStrokeColor(aContext, 1, 0, 0, 0.8);
375 CGContextSetLineWidth(aContext, 4.0);
376 CGContextStrokeRect(aContext, aRect);
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)
394 waitUntilDone:false];
398 bool nsWindow::IsTopLevel() {
399 return mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog ||
400 mWindowType == eWindowType_invisible;
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();
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;
432 ALOG("nsWindow[%p]::Create bounds: %d %d %d %d", (void*)this, mBounds.x, mBounds.y, mBounds.width,
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!");
444 [[ChildView alloc] initWithFrame:DevPixelsToUIKitPoints(mBounds, BackingScaleFactor())
446 mNativeView.hidden = YES;
449 parent->mChildren.AppendElement(this);
454 [nativeParent addSubview:mNativeView];
455 } else if (nsAppShell::gWindow) {
456 [nsAppShell::gWindow.rootViewController.view addSubview:mNativeView];
458 [nsAppShell::gTopLevelViews addObject:mNativeView];
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);
470 if (mParent) mParent->mChildren.RemoveElement(this);
472 [mNativeView widgetDestroyed];
474 nsBaseWidget::Destroy();
476 // ReportDestroyEvent();
480 nsBaseWidget::OnDestroy();
485 void nsWindow::Show(bool aState) {
486 if (aState != mVisible) {
487 mNativeView.hidden = aState ? NO : YES;
490 mParent ? mParent->mNativeView : nsAppShell::gWindow.rootViewController.view;
491 [parentView bringSubviewToFront:mNativeView];
492 [mNativeView setNeedsDisplay];
498 void nsWindow::Move(double aX, double aY) {
499 if (!mNativeView || (mBounds.x == aX && mBounds.y == aY)) return;
502 // The point we have is in Gecko coordinates (origin top-left). Convert
503 // it to Cocoa ones (origin bottom-left).
507 mNativeView.frame = DevPixelsToUIKitPoints(mBounds, BackingScaleFactor());
509 if (mVisible) [mNativeView setNeedsDisplay];
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;
524 mBounds.width = aWidth;
525 mBounds.height = aHeight;
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];
550 void nsWindow::SetSizeMode(nsSizeMode aMode) {
551 if (aMode == static_cast<int32_t>(mSizeMode)) {
555 mSizeMode = static_cast<nsSizeMode>(aMode);
556 if (aMode == nsSizeMode_Maximized || aMode == nsSizeMode_Fullscreen) {
557 // Resize to fill screen
558 nsBaseWidget::InfallibleMakeFullScreen(true);
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);
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();
597 void nsWindow::ReportMoveEvent() { NotifyWindowMoved(mBounds.x, mBounds.y); }
599 void nsWindow::ReportSizeModeEvent(nsSizeMode aMode) {
600 if (mWidgetListener) {
604 case nsSizeMode_Maximized:
605 theMode = nsSizeMode_Maximized;
607 case nsSizeMode_Fullscreen:
608 theMode = nsSizeMode_Fullscreen;
613 mWidgetListener->SizeModeChanged(theMode);
617 void nsWindow::ReportSizeEvent() {
618 if (mWidgetListener) {
619 LayoutDeviceIntRect innerBounds = GetClientBounds();
620 mWidgetListener->WindowResized(this, innerBounds.width, innerBounds.height);
624 LayoutDeviceIntRect nsWindow::GetScreenBounds() {
625 return LayoutDeviceIntRect(WidgetToScreenOffset(), mBounds.Size());
628 LayoutDeviceIntPoint nsWindow::WidgetToScreenOffset() {
629 LayoutDeviceIntPoint offset(0, 0);
631 offset = mParent->WidgetToScreenOffset();
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];
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);
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;
674 case NS_NATIVE_WIDGET:
675 case NS_NATIVE_DISPLAY:
676 retVal = (void*)mNativeView;
679 case NS_NATIVE_WINDOW:
680 retVal = [mNativeView window];
683 case NS_NATIVE_GRAPHIC:
684 NS_ERROR("Requesting NS_NATIVE_GRAPHIC on a UIKit child view!");
687 case NS_NATIVE_OFFSETX:
691 case NS_NATIVE_OFFSETY:
695 case NS_RAW_NATIVE_IME_CONTEXT:
696 retVal = GetPseudoIMEContext();
700 retVal = NS_ONLY_ONE_NATIVE_IME_CONTEXT;
707 CGFloat nsWindow::BackingScaleFactor() {
709 return [mNativeView contentScaleFactor];
711 return [UIScreen mainScreen].scale;
714 int32_t nsWindow::RoundsWidgetCoordinatesTo() {
715 if (BackingScaleFactor() == 2.0) {
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();