diff --git a/widget/windows/winrt/FrameworkView.cpp b/widget/windows/winrt/FrameworkView.cpp index a77712499f34..60b55a54b2ef 100644 --- a/widget/windows/winrt/FrameworkView.cpp +++ b/widget/windows/winrt/FrameworkView.cpp @@ -252,9 +252,7 @@ FrameworkView::GetBounds(nsIntRect &aRect) if (mShuttingDown) { return; } - nsIntRect mozrect(0, 0, (uint32_t)ceil(mWindowBounds.Width), - (uint32_t)ceil(mWindowBounds.Height)); - aRect = mozrect; + aRect = mWindowBounds; } void @@ -267,8 +265,7 @@ FrameworkView::UpdateWidgetSizeAndPosition() NS_ASSERTION(mWidget, "SetWidget must be called before UpdateWidgetSizeAndPosition!"); mWidget->Move(0, 0); - mWidget->Resize(0, 0, (uint32_t)ceil(mWindowBounds.Width), - (uint32_t)ceil(mWindowBounds.Height), true); + mWidget->Resize(0, 0, mWindowBounds.width, mWindowBounds.height, true); mWidget->SizeModeChanged(); } @@ -290,10 +287,14 @@ FrameworkView::IsVisible() const void FrameworkView::SetDpi(float aDpi) { if (aDpi != mDPI) { - mDPI = aDpi; - // Often a DPI change implies a window size change. - NS_ASSERTION(mWindow, "SetWindow must be called before SetDpi!"); - mWindow->get_Bounds(&mWindowBounds); + mDPI = aDpi; + // Often a DPI change implies a window size change. + NS_ASSERTION(mWindow, "SetWindow must be called before SetDpi!"); + Rect logicalBounds; + mWindow->get_Bounds(&logicalBounds); + + // convert to physical (device) pixels + mWindowBounds = MetroUtils::LogToPhys(logicalBounds); } } @@ -426,7 +427,9 @@ FrameworkView::OnWindowSizeChanged(ICoreWindow* aSender, IWindowSizeChangedEvent } NS_ASSERTION(mWindow, "SetWindow must be called before OnWindowSizeChanged!"); - mWindow->get_Bounds(&mWindowBounds); + Rect logicalBounds; + mWindow->get_Bounds(&logicalBounds); + mWindowBounds = MetroUtils::LogToPhys(logicalBounds); UpdateWidgetSizeAndPosition(); FireViewStateObservers(); diff --git a/widget/windows/winrt/FrameworkView.h b/widget/windows/winrt/FrameworkView.h index 813fba922710..a069c719594c 100644 --- a/widget/windows/winrt/FrameworkView.h +++ b/widget/windows/winrt/FrameworkView.h @@ -177,7 +177,7 @@ private: private: nsRefPtr mD2DWindowSurface; - Rect mWindowBounds; + nsIntRect mWindowBounds; // in device-pixel coordinates float mDPI; bool mShuttingDown; bool mPainting; diff --git a/widget/windows/winrt/MetroInput.cpp b/widget/windows/winrt/MetroInput.cpp index fd77a6aead51..40f8823bfb69 100644 --- a/widget/windows/winrt/MetroInput.cpp +++ b/widget/windows/winrt/MetroInput.cpp @@ -70,12 +70,10 @@ namespace { props->get_ContactRect(&contactRect); props->get_Pressure(&pressure); - nsIntPoint touchPoint; - touchPoint.x = static_cast(position.X); - touchPoint.y = static_cast(position.Y); + nsIntPoint touchPoint = MetroUtils::LogToPhys(position); nsIntPoint touchRadius; - touchRadius.x = static_cast(contactRect.Width) / 2; - touchRadius.y = static_cast(contactRect.Height) / 2; + touchRadius.x = MetroUtils::LogToPhys(contactRect.Width) / 2; + touchRadius.y = MetroUtils::LogToPhys(contactRect.Height) / 2; return new nsDOMTouch(pointerId, touchPoint, // Rotation radius and angle. @@ -261,9 +259,10 @@ namespace { aWParam |= MK_SHIFT; } + Foundation::Point logPoint = MetroUtils::PhysToLog(aEvent.refPoint); LParamForMouseEvents lParam; - lParam.parts.x = static_cast(aEvent.refPoint.x); - lParam.parts.y = static_cast(aEvent.refPoint.y); + lParam.parts.x = static_cast(NS_round(logPoint.X)); + lParam.parts.y = static_cast(NS_round(logPoint.Y)); aLParam = lParam.lParam; } } @@ -428,8 +427,7 @@ MetroInput::OnPointerWheelChanged(UI::Core::ICoreWindow* aSender, WheelEvent wheelEvent(true, NS_WHEEL_WHEEL, mWidget.Get()); mModifierKeyState.Update(); mModifierKeyState.InitInputEvent(wheelEvent); - wheelEvent.refPoint.x = POINT_CEIL_X(position); - wheelEvent.refPoint.y = POINT_CEIL_Y(position); + wheelEvent.refPoint = MetroUtils::LogToPhys(position); wheelEvent.time = timestamp; wheelEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE; wheelEvent.pressure = pressure; @@ -933,8 +931,7 @@ MetroInput::InitGeckoMouseEventFromPointerPoint( mModifierKeyState.Update(); mModifierKeyState.InitInputEvent(aEvent); - aEvent.refPoint.x = POINT_CEIL_X(position); - aEvent.refPoint.y = POINT_CEIL_Y(position); + aEvent.refPoint = MetroUtils::LogToPhys(position); aEvent.time = timestamp; if (!canBeDoubleTap) { @@ -1050,8 +1047,7 @@ MetroInput::ProcessManipulationDelta( mModifierKeyState.InitInputEvent(magEvent); magEvent.time = ::GetMessageTime(); magEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; - magEvent.refPoint.x = POINT_CEIL_X(aPosition); - magEvent.refPoint.y = POINT_CEIL_Y(aPosition); + magEvent.refPoint = MetroUtils::LogToPhys(aPosition); DispatchEventIgnoreStatus(&magEvent); // Send a gecko event indicating the rotation since the last update. @@ -1063,8 +1059,7 @@ MetroInput::ProcessManipulationDelta( mModifierKeyState.InitInputEvent(rotEvent); rotEvent.time = ::GetMessageTime(); rotEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; - rotEvent.refPoint.x = POINT_CEIL_X(aPosition); - rotEvent.refPoint.y = POINT_CEIL_Y(aPosition); + rotEvent.refPoint = MetroUtils::LogToPhys(aPosition); if (rotEvent.delta >= 0) { rotEvent.direction = nsIDOMSimpleGestureEvent::ROTATION_COUNTERCLOCKWISE; } else { @@ -1200,8 +1195,7 @@ MetroInput::OnManipulationCompleted( mModifierKeyState.InitInputEvent(swipeEvent); swipeEvent.time = ::GetMessageTime(); swipeEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; - swipeEvent.refPoint.x = POINT_CEIL_X(position); - swipeEvent.refPoint.y = POINT_CEIL_Y(position); + swipeEvent.refPoint = MetroUtils::LogToPhys(position); DispatchEventIgnoreStatus(&swipeEvent); } @@ -1216,8 +1210,7 @@ MetroInput::OnManipulationCompleted( mModifierKeyState.InitInputEvent(swipeEvent); swipeEvent.time = ::GetMessageTime(); swipeEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; - swipeEvent.refPoint.x = POINT_CEIL_X(position); - swipeEvent.refPoint.y = POINT_CEIL_Y(position); + swipeEvent.refPoint = MetroUtils::LogToPhys(position); DispatchEventIgnoreStatus(&swipeEvent); } @@ -1256,8 +1249,7 @@ MetroInput::OnTapped(UI::Input::IGestureRecognizer* aSender, nsMouseEvent::eNormal); mModifierKeyState.Update(); mModifierKeyState.InitInputEvent(mouseEvent); - mouseEvent.refPoint.x = POINT_CEIL_X(position); - mouseEvent.refPoint.y = POINT_CEIL_Y(position); + mouseEvent.refPoint = MetroUtils::LogToPhys(position); mouseEvent.time = ::GetMessageTime(); aArgs->get_TapCount(&mouseEvent.clickCount); mouseEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; @@ -1303,8 +1295,7 @@ MetroInput::OnRightTapped(UI::Input::IGestureRecognizer* aSender, nsMouseEvent::eNormal); mModifierKeyState.Update(); mModifierKeyState.InitInputEvent(contextMenu); - contextMenu.refPoint.x = POINT_CEIL_X(position); - contextMenu.refPoint.y = POINT_CEIL_Y(position); + contextMenu.refPoint = MetroUtils::LogToPhys(position); contextMenu.time = ::GetMessageTime(); MozInputSourceFromDeviceType(deviceType, contextMenu.inputSource); DispatchEventIgnoreStatus(&contextMenu); diff --git a/widget/windows/winrt/MetroUtils.cpp b/widget/windows/winrt/MetroUtils.cpp index 68ec059e6b8f..02a120f4d4f8 100644 --- a/widget/windows/winrt/MetroUtils.cpp +++ b/widget/windows/winrt/MetroUtils.cpp @@ -24,6 +24,7 @@ #include #include +#include using namespace ABI::Windows::UI::ApplicationSettings; @@ -33,12 +34,37 @@ using namespace ABI::Windows::Foundation; using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::Windows::UI::ViewManagement; +using namespace ABI::Windows::Graphics::Display; // File-scoped statics (unnamed namespace) namespace { #ifdef PR_LOGGING PRLogModuleInfo* metroWidgetLog = PR_NewLogModule("MetroWidget"); #endif + + FLOAT LogToPhysFactor() { + ComPtr dispProps; + if (SUCCEEDED(GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), + dispProps.GetAddressOf()))) { + FLOAT dpi; + if (SUCCEEDED(dispProps->get_LogicalDpi(&dpi))) { + return dpi / 96.0f; + } + } + return 1.0f; + } + + FLOAT PhysToLogFactor() { + ComPtr dispProps; + if (SUCCEEDED(GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), + dispProps.GetAddressOf()))) { + FLOAT dpi; + if (SUCCEEDED(dispProps->get_LogicalDpi(&dpi))) { + return 96.0f / dpi; + } + } + return 1.0f; + } }; void Log(const wchar_t *fmt, ...) @@ -77,6 +103,44 @@ void Log(const wchar_t *fmt, ...) #endif } +// Conversion between logical and physical coordinates +int32_t +MetroUtils::LogToPhys(FLOAT aValue) +{ + return int32_t(NS_round(aValue * LogToPhysFactor())); +} + +nsIntPoint +MetroUtils::LogToPhys(const Point& aPt) +{ + FLOAT factor = LogToPhysFactor(); + return nsIntPoint(int32_t(NS_round(aPt.X * factor)), int32_t(NS_round(aPt.Y * factor))); +} + +nsIntRect +MetroUtils::LogToPhys(const Rect& aRect) +{ + FLOAT factor = LogToPhysFactor(); + return nsIntRect(int32_t(NS_round(aRect.X * factor)), + int32_t(NS_round(aRect.Y * factor)), + int32_t(NS_round(aRect.Width * factor)), + int32_t(NS_round(aRect.Height * factor))); +} + +FLOAT +MetroUtils::PhysToLog(int32_t aValue) +{ + return FLOAT(aValue) * PhysToLogFactor(); +} + +Point +MetroUtils::PhysToLog(const nsIntPoint& aPt) +{ + FLOAT factor = PhysToLogFactor(); + Point p = { FLOAT(aPt.x) * factor, FLOAT(aPt.y) * factor }; + return p; +} + nsresult MetroUtils::FireObserver(const char* aMessage, const PRUnichar* aData) { diff --git a/widget/windows/winrt/MetroUtils.h b/widget/windows/winrt/MetroUtils.h index 4220b29e52c8..153c04754335 100644 --- a/widget/windows/winrt/MetroUtils.h +++ b/widget/windows/winrt/MetroUtils.h @@ -8,6 +8,8 @@ #include "nsDebug.h" #include "nsThreadUtils.h" #include "nsString.h" +#include "nsPoint.h" +#include "nsRect.h" #include "mozwrlbase.h" @@ -76,8 +78,19 @@ class MetroUtils typedef ABI::Windows::Foundation::IUriRuntimeClass IUriRuntimeClass; typedef Microsoft::WRL::Wrappers::HString HString; typedef ABI::Windows::UI::ViewManagement::ApplicationViewState ApplicationViewState; + typedef ABI::Windows::Foundation::Point Point; + typedef ABI::Windows::Foundation::Rect Rect; public: + // Functions to convert between logical pixels as used by most Windows APIs + // and physical (device) pixels. + // See MSDN documentation about DIPs (device independent pixels) for details. + static int32_t LogToPhys(FLOAT aValue); + static nsIntPoint LogToPhys(const Point& aPt); + static nsIntRect LogToPhys(const Rect& aRect); + static FLOAT PhysToLog(int32_t aValue); + static Point PhysToLog(const nsIntPoint& aPt); + static nsresult FireObserver(const char* aMessage, const PRUnichar* aData = nullptr); static HRESULT CreateUri(HSTRING aUriStr, Microsoft::WRL::ComPtr& aUriOut); diff --git a/widget/windows/winrt/MetroWidget.cpp b/widget/windows/winrt/MetroWidget.cpp index 1a3b87f46920..59560aabfe06 100644 --- a/widget/windows/winrt/MetroWidget.cpp +++ b/widget/windows/winrt/MetroWidget.cpp @@ -21,6 +21,7 @@ #include "nsTextStore.h" #include "Layers.h" #include "BasicLayers.h" +#include "Windows.Graphics.Display.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -38,6 +39,7 @@ using namespace ABI::Windows::Devices::Input; using namespace ABI::Windows::UI::Core; using namespace ABI::Windows::System; using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Graphics::Display; #ifdef PR_LOGGING extern PRLogModuleInfo* gWindowsLog; @@ -941,9 +943,11 @@ MetroWidget::InitEvent(nsGUIEvent& event, nsIntPoint* aPoint) { if (!aPoint) { event.refPoint.x = event.refPoint.y = 0; - } else { - event.refPoint.x = aPoint->x; - event.refPoint.y = aPoint->y; + } else { + // convert CSS pixels to device pixels for event.refPoint + double scale = GetDefaultScale(); + event.refPoint.x = int32_t(NS_round(aPoint->x * scale)); + event.refPoint.y = int32_t(NS_round(aPoint->y * scale)); } event.time = ::GetMessageTime(); } @@ -1015,6 +1019,21 @@ MetroWidget::GetRootAccessible() } #endif +double MetroWidget::GetDefaultScaleInternal() +{ + // Return the resolution scale factor reported by the metro environment. + // XXX TODO: also consider the desktop resolution setting, as IE appears to do? + ComPtr dispProps; + if (SUCCEEDED(GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), + dispProps.GetAddressOf()))) { + ResolutionScale scale; + if (SUCCEEDED(dispProps->get_ResolutionScale(&scale))) { + return (double)scale / 100.0; + } + } + return 1.0; +} + float MetroWidget::GetDPI() { LogFunction(); diff --git a/widget/windows/winrt/MetroWidget.h b/widget/windows/winrt/MetroWidget.h index 48609157f319..6b58604c057b 100644 --- a/widget/windows/winrt/MetroWidget.h +++ b/widget/windows/winrt/MetroWidget.h @@ -110,6 +110,7 @@ public: uint32_t aModifierFlags, uint32_t aAdditionalFlags); virtual bool HasPendingInputEvent(); + virtual double GetDefaultScaleInternal(); float GetDPI(); virtual bool IsVisible() const; virtual bool IsEnabled() const;