bug 816709 - HiDPI support for Win8 Metro. r=jimm

This commit is contained in:
Jonathan Kew 2013-03-13 15:09:46 +00:00
parent 7c59801006
commit da96cdb204
7 changed files with 128 additions and 37 deletions

View File

@ -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();

View File

@ -177,7 +177,7 @@ private:
private:
nsRefPtr<gfxD2DSurface> mD2DWindowSurface;
Rect mWindowBounds;
nsIntRect mWindowBounds; // in device-pixel coordinates
float mDPI;
bool mShuttingDown;
bool mPainting;

View File

@ -70,12 +70,10 @@ namespace {
props->get_ContactRect(&contactRect);
props->get_Pressure(&pressure);
nsIntPoint touchPoint;
touchPoint.x = static_cast<int32_t>(position.X);
touchPoint.y = static_cast<int32_t>(position.Y);
nsIntPoint touchPoint = MetroUtils::LogToPhys(position);
nsIntPoint touchRadius;
touchRadius.x = static_cast<int32_t>(contactRect.Width) / 2;
touchRadius.y = static_cast<int32_t>(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<uint16_t>(aEvent.refPoint.x);
lParam.parts.y = static_cast<uint16_t>(aEvent.refPoint.y);
lParam.parts.x = static_cast<uint16_t>(NS_round(logPoint.X));
lParam.parts.y = static_cast<uint16_t>(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);

View File

@ -24,6 +24,7 @@
#include <wrl/wrappers/corewrappers.h>
#include <windows.ui.applicationsettings.h>
#include <windows.graphics.display.h>
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<IDisplayPropertiesStatics> 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<IDisplayPropertiesStatics> 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)
{

View File

@ -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<IUriRuntimeClass>& aUriOut);

View File

@ -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<IDisplayPropertiesStatics> 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();

View File

@ -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;