import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,453 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <windows.h>
#include <audiopolicy.h>
#include <mmdeviceapi.h>
#include "mozilla/RefPtr.h"
#include "nsIStringBundle.h"
#include "nsIUUIDGenerator.h"
#include "nsIXULAppInfo.h"
//#include "AudioSession.h"
#include "nsCOMPtr.h"
#include "nsServiceManagerUtils.h"
#include "nsString.h"
#include "nsThreadUtils.h"
#include "nsXULAppAPI.h"
#include "mozilla/Attributes.h"
#include <objbase.h>
namespace mozilla {
namespace widget {
/*
* To take advantage of what Vista+ have to offer with respect to audio,
* we need to maintain an audio session. This class wraps IAudioSessionControl
* and implements IAudioSessionEvents (for callbacks from Windows)
*/
class AudioSession final : public IAudioSessionEvents {
private:
AudioSession();
~AudioSession();
public:
static AudioSession* GetSingleton();
// COM IUnknown
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP QueryInterface(REFIID, void**);
STDMETHODIMP_(ULONG) Release();
// IAudioSessionEvents
STDMETHODIMP OnChannelVolumeChanged(DWORD aChannelCount,
float aChannelVolumeArray[],
DWORD aChangedChannel,
LPCGUID aContext);
STDMETHODIMP OnDisplayNameChanged(LPCWSTR aDisplayName, LPCGUID aContext);
STDMETHODIMP OnGroupingParamChanged(LPCGUID aGroupingParam, LPCGUID aContext);
STDMETHODIMP OnIconPathChanged(LPCWSTR aIconPath, LPCGUID aContext);
STDMETHODIMP OnSessionDisconnected(AudioSessionDisconnectReason aReason);
private:
nsresult OnSessionDisconnectedInternal();
public:
STDMETHODIMP OnSimpleVolumeChanged(float aVolume,
BOOL aMute,
LPCGUID aContext);
STDMETHODIMP OnStateChanged(AudioSessionState aState);
nsresult Start();
nsresult Stop();
void StopInternal();
nsresult GetSessionData(nsID& aID,
nsString& aSessionName,
nsString& aIconPath);
nsresult SetSessionData(const nsID& aID,
const nsString& aSessionName,
const nsString& aIconPath);
enum SessionState {
UNINITIALIZED, // Has not been initialized yet
STARTED, // Started
CLONED, // SetSessionInfoCalled, Start not called
FAILED, // The audio session failed to start
STOPPED, // Stop called
AUDIO_SESSION_DISCONNECTED // Audio session disconnected
};
protected:
RefPtr<IAudioSessionControl> mAudioSessionControl;
nsString mDisplayName;
nsString mIconPath;
nsID mSessionGroupingParameter;
SessionState mState;
ThreadSafeAutoRefCnt mRefCnt;
NS_DECL_OWNINGTHREAD
static AudioSession* sService;
};
nsresult
StartAudioSession()
{
return AudioSession::GetSingleton()->Start();
}
nsresult
StopAudioSession()
{
return AudioSession::GetSingleton()->Stop();
}
nsresult
GetAudioSessionData(nsID& aID,
nsString& aSessionName,
nsString& aIconPath)
{
return AudioSession::GetSingleton()->GetSessionData(aID,
aSessionName,
aIconPath);
}
nsresult
RecvAudioSessionData(const nsID& aID,
const nsString& aSessionName,
const nsString& aIconPath)
{
return AudioSession::GetSingleton()->SetSessionData(aID,
aSessionName,
aIconPath);
}
AudioSession* AudioSession::sService = nullptr;
AudioSession::AudioSession()
{
mState = UNINITIALIZED;
}
AudioSession::~AudioSession()
{
}
AudioSession*
AudioSession::GetSingleton()
{
if (!(AudioSession::sService)) {
RefPtr<AudioSession> service = new AudioSession();
service.forget(&AudioSession::sService);
}
// We don't refcount AudioSession on the Gecko side, we hold one single ref
// as long as the appshell is running.
return AudioSession::sService;
}
// It appears Windows will use us on a background thread ...
NS_IMPL_ADDREF(AudioSession)
NS_IMPL_RELEASE(AudioSession)
STDMETHODIMP
AudioSession::QueryInterface(REFIID iid, void **ppv)
{
const IID IID_IAudioSessionEvents = __uuidof(IAudioSessionEvents);
if ((IID_IUnknown == iid) ||
(IID_IAudioSessionEvents == iid)) {
*ppv = static_cast<IAudioSessionEvents*>(this);
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
// Once we are started Windows will hold a reference to us through our
// IAudioSessionEvents interface that will keep us alive until the appshell
// calls Stop.
nsresult
AudioSession::Start()
{
MOZ_ASSERT(mState == UNINITIALIZED ||
mState == CLONED ||
mState == AUDIO_SESSION_DISCONNECTED,
"State invariants violated");
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
const IID IID_IAudioSessionManager = __uuidof(IAudioSessionManager);
HRESULT hr;
// There's a matching CoUninit in Stop() for this tied to a state of
// UNINITIALIZED.
hr = CoInitialize(nullptr);
MOZ_ASSERT(SUCCEEDED(hr), "CoInitialize failure in audio session control, unexpected");
if (mState == UNINITIALIZED) {
mState = FAILED;
// Content processes should be CLONED
if (XRE_IsContentProcess()) {
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(XRE_IsParentProcess(),
"Should only get here in a chrome process!");
nsCOMPtr<nsIStringBundleService> bundleService =
do_GetService(NS_STRINGBUNDLE_CONTRACTID);
NS_ENSURE_TRUE(bundleService, NS_ERROR_FAILURE);
nsCOMPtr<nsIStringBundle> bundle;
bundleService->CreateBundle("chrome://branding/locale/brand.properties",
getter_AddRefs(bundle));
NS_ENSURE_TRUE(bundle, NS_ERROR_FAILURE);
bundle->GetStringFromName(u"brandFullName",
getter_Copies(mDisplayName));
wchar_t *buffer;
mIconPath.GetMutableData(&buffer, MAX_PATH);
::GetModuleFileNameW(nullptr, buffer, MAX_PATH);
nsCOMPtr<nsIUUIDGenerator> uuidgen =
do_GetService("@mozilla.org/uuid-generator;1");
NS_ENSURE_TRUE(uuidgen, NS_ERROR_FAILURE);
uuidgen->GenerateUUIDInPlace(&mSessionGroupingParameter);
}
mState = FAILED;
MOZ_ASSERT(!mDisplayName.IsEmpty() || !mIconPath.IsEmpty(),
"Should never happen ...");
RefPtr<IMMDeviceEnumerator> enumerator;
hr = ::CoCreateInstance(CLSID_MMDeviceEnumerator,
nullptr,
CLSCTX_ALL,
IID_IMMDeviceEnumerator,
getter_AddRefs(enumerator));
if (FAILED(hr))
return NS_ERROR_NOT_AVAILABLE;
RefPtr<IMMDevice> device;
hr = enumerator->GetDefaultAudioEndpoint(EDataFlow::eRender,
ERole::eMultimedia,
getter_AddRefs(device));
if (FAILED(hr)) {
if (hr == E_NOTFOUND)
return NS_ERROR_NOT_AVAILABLE;
return NS_ERROR_FAILURE;
}
RefPtr<IAudioSessionManager> manager;
hr = device->Activate(IID_IAudioSessionManager,
CLSCTX_ALL,
nullptr,
getter_AddRefs(manager));
if (FAILED(hr)) {
return NS_ERROR_FAILURE;
}
hr = manager->GetAudioSessionControl(&GUID_NULL,
0,
getter_AddRefs(mAudioSessionControl));
if (FAILED(hr)) {
return NS_ERROR_FAILURE;
}
hr = mAudioSessionControl->SetGroupingParam((LPGUID)&mSessionGroupingParameter,
nullptr);
if (FAILED(hr)) {
StopInternal();
return NS_ERROR_FAILURE;
}
hr = mAudioSessionControl->SetDisplayName(mDisplayName.get(), nullptr);
if (FAILED(hr)) {
StopInternal();
return NS_ERROR_FAILURE;
}
hr = mAudioSessionControl->SetIconPath(mIconPath.get(), nullptr);
if (FAILED(hr)) {
StopInternal();
return NS_ERROR_FAILURE;
}
// Increments refcount of 'this'.
hr = mAudioSessionControl->RegisterAudioSessionNotification(this);
if (FAILED(hr)) {
StopInternal();
return NS_ERROR_FAILURE;
}
mState = STARTED;
return NS_OK;
}
void
AudioSession::StopInternal()
{
if (mAudioSessionControl &&
(mState == STARTED || mState == STOPPED)) {
// Decrement refcount of 'this'
mAudioSessionControl->UnregisterAudioSessionNotification(this);
}
mAudioSessionControl = nullptr;
}
nsresult
AudioSession::Stop()
{
MOZ_ASSERT(mState == STARTED ||
mState == UNINITIALIZED || // XXXremove this
mState == FAILED,
"State invariants violated");
SessionState state = mState;
mState = STOPPED;
{
RefPtr<AudioSession> kungFuDeathGrip;
kungFuDeathGrip.swap(sService);
StopInternal();
}
if (state != UNINITIALIZED) {
::CoUninitialize();
}
return NS_OK;
}
void CopynsID(nsID& lhs, const nsID& rhs)
{
lhs.m0 = rhs.m0;
lhs.m1 = rhs.m1;
lhs.m2 = rhs.m2;
for (int i = 0; i < 8; i++ ) {
lhs.m3[i] = rhs.m3[i];
}
}
nsresult
AudioSession::GetSessionData(nsID& aID,
nsString& aSessionName,
nsString& aIconPath)
{
MOZ_ASSERT(mState == FAILED ||
mState == STARTED ||
mState == CLONED,
"State invariants violated");
CopynsID(aID, mSessionGroupingParameter);
aSessionName = mDisplayName;
aIconPath = mIconPath;
if (mState == FAILED)
return NS_ERROR_FAILURE;
return NS_OK;
}
nsresult
AudioSession::SetSessionData(const nsID& aID,
const nsString& aSessionName,
const nsString& aIconPath)
{
MOZ_ASSERT(mState == UNINITIALIZED,
"State invariants violated");
MOZ_ASSERT(!XRE_IsParentProcess(),
"Should never get here in a chrome process!");
mState = CLONED;
CopynsID(mSessionGroupingParameter, aID);
mDisplayName = aSessionName;
mIconPath = aIconPath;
return NS_OK;
}
STDMETHODIMP
AudioSession::OnChannelVolumeChanged(DWORD aChannelCount,
float aChannelVolumeArray[],
DWORD aChangedChannel,
LPCGUID aContext)
{
return S_OK; // NOOP
}
STDMETHODIMP
AudioSession::OnDisplayNameChanged(LPCWSTR aDisplayName,
LPCGUID aContext)
{
return S_OK; // NOOP
}
STDMETHODIMP
AudioSession::OnGroupingParamChanged(LPCGUID aGroupingParam,
LPCGUID aContext)
{
return S_OK; // NOOP
}
STDMETHODIMP
AudioSession::OnIconPathChanged(LPCWSTR aIconPath,
LPCGUID aContext)
{
return S_OK; // NOOP
}
STDMETHODIMP
AudioSession::OnSessionDisconnected(AudioSessionDisconnectReason aReason)
{
// Run our code asynchronously. Per MSDN we can't do anything interesting
// in this callback.
nsCOMPtr<nsIRunnable> runnable =
NewRunnableMethod(this, &AudioSession::OnSessionDisconnectedInternal);
NS_DispatchToMainThread(runnable);
return S_OK;
}
nsresult
AudioSession::OnSessionDisconnectedInternal()
{
if (!mAudioSessionControl)
return NS_OK;
// When successful, UnregisterAudioSessionNotification will decrement the
// refcount of 'this'. Start will re-increment it. In the interim,
// we'll need to reference ourselves.
RefPtr<AudioSession> kungFuDeathGrip(this);
mAudioSessionControl->UnregisterAudioSessionNotification(this);
mAudioSessionControl = nullptr;
mState = AUDIO_SESSION_DISCONNECTED;
CoUninitialize();
Start(); // If it fails there's not much we can do.
return NS_OK;
}
STDMETHODIMP
AudioSession::OnSimpleVolumeChanged(float aVolume,
BOOL aMute,
LPCGUID aContext)
{
return S_OK; // NOOP
}
STDMETHODIMP
AudioSession::OnStateChanged(AudioSessionState aState)
{
return S_OK; // NOOP
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,30 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsString.h"
namespace mozilla {
namespace widget {
// Start the audio session in the current process
nsresult StartAudioSession();
// Pass the information necessary to start an audio session in another process
nsresult GetAudioSessionData(nsID& aID,
nsString& aSessionName,
nsString& aIconPath);
// Receive the information necessary to start an audio session in a non-chrome
// process
nsresult RecvAudioSessionData(const nsID& aID,
const nsString& aSessionName,
const nsString& aIconPath);
// Stop the audio session in the current process
nsresult StopAudioSession();
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,78 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CompositorWidgetChild.h"
#include "mozilla/Unused.h"
#include "mozilla/widget/CompositorWidgetVsyncObserver.h"
#include "nsBaseWidget.h"
#include "VsyncDispatcher.h"
namespace mozilla {
namespace widget {
CompositorWidgetChild::CompositorWidgetChild(RefPtr<CompositorVsyncDispatcher> aVsyncDispatcher,
RefPtr<CompositorWidgetVsyncObserver> aVsyncObserver)
: mVsyncDispatcher(aVsyncDispatcher),
mVsyncObserver(aVsyncObserver)
{
MOZ_ASSERT(XRE_IsParentProcess());
}
CompositorWidgetChild::~CompositorWidgetChild()
{
}
void
CompositorWidgetChild::EnterPresentLock()
{
Unused << SendEnterPresentLock();
}
void
CompositorWidgetChild::LeavePresentLock()
{
Unused << SendLeavePresentLock();
}
void
CompositorWidgetChild::OnDestroyWindow()
{
}
void
CompositorWidgetChild::UpdateTransparency(nsTransparencyMode aMode)
{
Unused << SendUpdateTransparency(static_cast<int32_t>(aMode));
}
void
CompositorWidgetChild::ClearTransparentWindow()
{
Unused << SendClearTransparentWindow();
}
HDC
CompositorWidgetChild::GetTransparentDC() const
{
// Not supported in out-of-process mode.
return nullptr;
}
bool
CompositorWidgetChild::RecvObserveVsync()
{
mVsyncDispatcher->SetCompositorVsyncObserver(mVsyncObserver);
return true;
}
bool
CompositorWidgetChild::RecvUnobserveVsync()
{
mVsyncDispatcher->SetCompositorVsyncObserver(nullptr);
return true;
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,45 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef widget_windows_CompositorWidgetChild_h
#define widget_windows_CompositorWidgetChild_h
#include "WinCompositorWidget.h"
#include "mozilla/widget/PCompositorWidgetChild.h"
#include "mozilla/widget/CompositorWidgetVsyncObserver.h"
namespace mozilla {
class CompositorVsyncDispatcher;
namespace widget {
class CompositorWidgetChild final
: public PCompositorWidgetChild,
public CompositorWidgetDelegate
{
public:
CompositorWidgetChild(RefPtr<CompositorVsyncDispatcher> aVsyncDispatcher,
RefPtr<CompositorWidgetVsyncObserver> aVsyncObserver);
~CompositorWidgetChild() override;
void EnterPresentLock() override;
void LeavePresentLock() override;
void OnDestroyWindow() override;
void UpdateTransparency(nsTransparencyMode aMode) override;
void ClearTransparentWindow() override;
HDC GetTransparentDC() const override;
bool RecvObserveVsync() override;
bool RecvUnobserveVsync() override;
private:
RefPtr<CompositorVsyncDispatcher> mVsyncDispatcher;
RefPtr<CompositorWidgetVsyncObserver> mVsyncObserver;
};
} // namespace widget
} // namespace mozilla
#endif // widget_windows_CompositorWidgetChild_h

View file

@ -0,0 +1,81 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CompositorWidgetParent.h"
#include "mozilla/Unused.h"
namespace mozilla {
namespace widget {
CompositorWidgetParent::CompositorWidgetParent(const CompositorWidgetInitData& aInitData)
: WinCompositorWidget(aInitData)
{
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
}
CompositorWidgetParent::~CompositorWidgetParent()
{
}
bool
CompositorWidgetParent::RecvEnterPresentLock()
{
EnterPresentLock();
return true;
}
bool
CompositorWidgetParent::RecvLeavePresentLock()
{
LeavePresentLock();
return true;
}
bool
CompositorWidgetParent::RecvUpdateTransparency(const int32_t& aMode)
{
UpdateTransparency(static_cast<nsTransparencyMode>(aMode));
return true;
}
bool
CompositorWidgetParent::RecvClearTransparentWindow()
{
ClearTransparentWindow();
return true;
}
nsIWidget*
CompositorWidgetParent::RealWidget()
{
return nullptr;
}
void
CompositorWidgetParent::ObserveVsync(VsyncObserver* aObserver)
{
if (aObserver) {
Unused << SendObserveVsync();
} else {
Unused << SendUnobserveVsync();
}
mVsyncObserver = aObserver;
}
RefPtr<VsyncObserver>
CompositorWidgetParent::GetVsyncObserver() const
{
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
return mVsyncObserver;
}
void
CompositorWidgetParent::ActorDestroy(ActorDestroyReason aWhy)
{
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,40 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _widget_windows_WinCompositorWidget_h__
#define _widget_windows_WinCompositorWidget_h__
#include "WinCompositorWidget.h"
#include "mozilla/widget/PCompositorWidgetParent.h"
namespace mozilla {
namespace widget {
class CompositorWidgetParent final
: public PCompositorWidgetParent,
public WinCompositorWidget
{
public:
CompositorWidgetParent(const CompositorWidgetInitData& aInitData);
~CompositorWidgetParent() override;
bool RecvEnterPresentLock() override;
bool RecvLeavePresentLock() override;
bool RecvUpdateTransparency(const int32_t& aMode) override;
bool RecvClearTransparentWindow() override;
void ActorDestroy(ActorDestroyReason aWhy) override;
nsIWidget* RealWidget() override;
void ObserveVsync(VsyncObserver* aObserver) override;
RefPtr<VsyncObserver> GetVsyncObserver() const override;
private:
RefPtr<VsyncObserver> mVsyncObserver;
};
} // namespace widget
} // namespace mozilla
#endif // _widget_windows_WinCompositorWidget_h__

1450
widget/windows/GfxInfo.cpp Normal file

File diff suppressed because it is too large Load diff

102
widget/windows/GfxInfo.h Normal file
View file

@ -0,0 +1,102 @@
/* vim: se cin sw=2 ts=2 et : */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __mozilla_widget_GfxInfo_h__
#define __mozilla_widget_GfxInfo_h__
#include "GfxInfoBase.h"
namespace mozilla {
namespace widget {
class GfxInfo : public GfxInfoBase
{
~GfxInfo() {}
public:
GfxInfo();
// We only declare the subset of nsIGfxInfo that we actually implement. The
// rest is brought forward from GfxInfoBase.
NS_IMETHOD GetD2DEnabled(bool *aD2DEnabled) override;
NS_IMETHOD GetDWriteEnabled(bool *aDWriteEnabled) override;
NS_IMETHOD GetDWriteVersion(nsAString & aDwriteVersion) override;
NS_IMETHOD GetCleartypeParameters(nsAString & aCleartypeParams) override;
NS_IMETHOD GetAdapterDescription(nsAString & aAdapterDescription) override;
NS_IMETHOD GetAdapterDriver(nsAString & aAdapterDriver) override;
NS_IMETHOD GetAdapterVendorID(nsAString & aAdapterVendorID) override;
NS_IMETHOD GetAdapterDeviceID(nsAString & aAdapterDeviceID) override;
NS_IMETHOD GetAdapterSubsysID(nsAString & aAdapterSubsysID) override;
NS_IMETHOD GetAdapterRAM(nsAString & aAdapterRAM) override;
NS_IMETHOD GetAdapterDriverVersion(nsAString & aAdapterDriverVersion) override;
NS_IMETHOD GetAdapterDriverDate(nsAString & aAdapterDriverDate) override;
NS_IMETHOD GetAdapterDescription2(nsAString & aAdapterDescription) override;
NS_IMETHOD GetAdapterDriver2(nsAString & aAdapterDriver) override;
NS_IMETHOD GetAdapterVendorID2(nsAString & aAdapterVendorID) override;
NS_IMETHOD GetAdapterDeviceID2(nsAString & aAdapterDeviceID) override;
NS_IMETHOD GetAdapterSubsysID2(nsAString & aAdapterSubsysID) override;
NS_IMETHOD GetAdapterRAM2(nsAString & aAdapterRAM) override;
NS_IMETHOD GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion) override;
NS_IMETHOD GetAdapterDriverDate2(nsAString & aAdapterDriverDate) override;
NS_IMETHOD GetIsGPU2Active(bool *aIsGPU2Active) override;
using GfxInfoBase::GetFeatureStatus;
using GfxInfoBase::GetFeatureSuggestedDriverVersion;
using GfxInfoBase::GetWebGLParameter;
virtual nsresult Init() override;
virtual uint32_t OperatingSystemVersion() override { return mWindowsVersion; }
nsresult FindMonitors(JSContext* cx, JS::HandleObject array) override;
#ifdef DEBUG
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIGFXINFODEBUG
#endif
protected:
virtual nsresult GetFeatureStatusImpl(int32_t aFeature,
int32_t *aStatus,
nsAString & aSuggestedDriverVersion,
const nsTArray<GfxDriverInfo>& aDriverInfo,
nsACString& aFailureId,
OperatingSystem* aOS = nullptr) override;
virtual const nsTArray<GfxDriverInfo>& GetGfxDriverInfo() override;
void DescribeFeatures(JSContext* cx, JS::Handle<JSObject*> aOut) override;
private:
void AddCrashReportAnnotations();
nsString mDeviceString;
nsString mDeviceID;
nsString mDriverVersion;
nsString mDriverDate;
nsString mDeviceKey;
nsString mDeviceKeyDebug;
nsString mAdapterVendorID;
nsString mAdapterDeviceID;
nsString mAdapterSubsysID;
nsString mDeviceString2;
nsString mDriverVersion2;
nsString mDeviceID2;
nsString mDriverDate2;
nsString mDeviceKey2;
nsString mAdapterVendorID2;
nsString mAdapterDeviceID2;
nsString mAdapterSubsysID2;
uint32_t mWindowsVersion;
bool mHasDualGPU;
bool mIsGPU2Active;
bool mHasDriverVersionMismatch;
};
} // namespace widget
} // namespace mozilla
#endif /* __mozilla_widget_GfxInfo_h__ */

173
widget/windows/IEnumFE.cpp Normal file
View file

@ -0,0 +1,173 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "IEnumFE.h"
#include "nsAlgorithm.h"
#include <algorithm>
CEnumFormatEtc::CEnumFormatEtc() :
mRefCnt(0),
mCurrentIdx(0)
{
}
// Constructor used by Clone()
CEnumFormatEtc::CEnumFormatEtc(nsTArray<FormatEtc>& aArray) :
mRefCnt(0),
mCurrentIdx(0)
{
// a deep copy, calls FormatEtc's copy constructor on each
mFormatList.AppendElements(aArray);
}
CEnumFormatEtc::~CEnumFormatEtc()
{
}
/* IUnknown impl. */
STDMETHODIMP
CEnumFormatEtc::QueryInterface(REFIID riid, LPVOID *ppv)
{
*ppv = nullptr;
if (IsEqualIID(riid, IID_IUnknown) ||
IsEqualIID(riid, IID_IEnumFORMATETC))
*ppv = (LPVOID)this;
if (*ppv == nullptr)
return E_NOINTERFACE;
// AddRef any interface we'll return.
((LPUNKNOWN)*ppv)->AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG)
CEnumFormatEtc::AddRef()
{
++mRefCnt;
NS_LOG_ADDREF(this, mRefCnt, "CEnumFormatEtc",sizeof(*this));
return mRefCnt;
}
STDMETHODIMP_(ULONG)
CEnumFormatEtc::Release()
{
uint32_t refReturn;
refReturn = --mRefCnt;
NS_LOG_RELEASE(this, mRefCnt, "CEnumFormatEtc");
if (mRefCnt == 0)
delete this;
return refReturn;
}
/* IEnumFORMATETC impl. */
STDMETHODIMP
CEnumFormatEtc::Next(ULONG aMaxToFetch, FORMATETC *aResult, ULONG *aNumFetched)
{
// If the method retrieves the number of items requested, the return
// value is S_OK. Otherwise, it is S_FALSE.
if (aNumFetched)
*aNumFetched = 0;
// aNumFetched can be null if aMaxToFetch is 1
if (!aNumFetched && aMaxToFetch > 1)
return S_FALSE;
if (!aResult)
return S_FALSE;
// We're done walking the list
if (mCurrentIdx >= mFormatList.Length())
return S_FALSE;
uint32_t left = mFormatList.Length() - mCurrentIdx;
if (!aMaxToFetch)
return S_FALSE;
uint32_t count = std::min(static_cast<uint32_t>(aMaxToFetch), left);
uint32_t idx = 0;
while (count > 0) {
// Copy out to aResult
mFormatList[mCurrentIdx++].CopyOut(&aResult[idx++]);
count--;
}
if (aNumFetched)
*aNumFetched = idx;
return S_OK;
}
STDMETHODIMP
CEnumFormatEtc::Skip(ULONG aSkipNum)
{
// If the method skips the number of items requested, the return value is S_OK.
// Otherwise, it is S_FALSE.
if ((mCurrentIdx + aSkipNum) >= mFormatList.Length())
return S_FALSE;
mCurrentIdx += aSkipNum;
return S_OK;
}
STDMETHODIMP
CEnumFormatEtc::Reset(void)
{
mCurrentIdx = 0;
return S_OK;
}
STDMETHODIMP
CEnumFormatEtc::Clone(LPENUMFORMATETC *aResult)
{
// Must return a new IEnumFORMATETC interface with the same iterative state.
if (!aResult)
return E_INVALIDARG;
CEnumFormatEtc * pEnumObj = new CEnumFormatEtc(mFormatList);
if (!pEnumObj)
return E_OUTOFMEMORY;
pEnumObj->AddRef();
pEnumObj->SetIndex(mCurrentIdx);
*aResult = pEnumObj;
return S_OK;
}
/* utils */
void
CEnumFormatEtc::AddFormatEtc(LPFORMATETC aFormat)
{
if (!aFormat)
return;
FormatEtc * etc = mFormatList.AppendElement();
// Make a copy of aFormat
if (etc)
etc->CopyIn(aFormat);
}
/* private */
void
CEnumFormatEtc::SetIndex(uint32_t aIdx)
{
mCurrentIdx = aIdx;
}

90
widget/windows/IEnumFE.h Normal file
View file

@ -0,0 +1,90 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef IEnumeFE_h__
#define IEnumeFE_h__
/*
* CEnumFormatEtc - implements IEnumFORMATETC
*/
#include <ole2.h>
#include "nsTArray.h"
#include "mozilla/Attributes.h"
// FORMATETC container
class FormatEtc
{
public:
FormatEtc() { memset(&mFormat, 0, sizeof(FORMATETC)); }
FormatEtc(const FormatEtc& copy) { CopyIn(&copy.mFormat); }
~FormatEtc() { if (mFormat.ptd) CoTaskMemFree(mFormat.ptd); }
void CopyIn(const FORMATETC *aSrc) {
if (!aSrc) {
memset(&mFormat, 0, sizeof(FORMATETC));
return;
}
mFormat = *aSrc;
if (aSrc->ptd) {
mFormat.ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE));
*(mFormat.ptd) = *(aSrc->ptd);
}
}
void CopyOut(LPFORMATETC aDest) {
if (!aDest)
return;
*aDest = mFormat;
if (mFormat.ptd) {
aDest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE));
*(aDest->ptd) = *(mFormat.ptd);
}
}
private:
FORMATETC mFormat;
};
/*
* CEnumFormatEtc is created within IDataObject::EnumFormatEtc. This object lives
* on its own, that is, QueryInterface only knows IUnknown and IEnumFormatEtc,
* nothing more. We still use an outer unknown for reference counting, because as
* long as this enumerator lives, the data object should live, thereby keeping the
* application up.
*/
class CEnumFormatEtc final : public IEnumFORMATETC
{
public:
CEnumFormatEtc(nsTArray<FormatEtc>& aArray);
CEnumFormatEtc();
~CEnumFormatEtc();
// IUnknown impl.
STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppv);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// IEnumFORMATETC impl.
STDMETHODIMP Next(ULONG aMaxToFetch, FORMATETC *aResult, ULONG *aNumFetched);
STDMETHODIMP Skip(ULONG aSkipNum);
STDMETHODIMP Reset();
STDMETHODIMP Clone(LPENUMFORMATETC *aResult); // Addrefs
// Utils
void AddFormatEtc(LPFORMATETC aFormat);
private:
nsTArray<FormatEtc> mFormatList; // Formats
ULONG mRefCnt; // Object reference count
ULONG mCurrentIdx; // Current element
void SetIndex(uint32_t aIdx);
};
#endif //_IENUMFE_H_

File diff suppressed because it is too large Load diff

495
widget/windows/IMMHandler.h Normal file
View file

@ -0,0 +1,495 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef IMMHandler_h_
#define IMMHandler_h_
#include "nscore.h"
#include <windows.h>
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsIWidget.h"
#include "mozilla/EventForwards.h"
#include "mozilla/TextEventDispatcher.h"
#include "nsRect.h"
#include "WritingModes.h"
#include "npapi.h"
class nsWindow;
class nsWindowBase;
namespace mozilla {
namespace widget {
struct MSGResult;
class IMEContext final
{
public:
IMEContext()
: mWnd(nullptr)
, mIMC(nullptr)
{
}
explicit IMEContext(HWND aWnd);
explicit IMEContext(nsWindowBase* aWindowBase);
~IMEContext()
{
Clear();
}
HIMC get() const
{
return mIMC;
}
void Init(HWND aWnd);
void Init(nsWindowBase* aWindowBase);
void Clear();
bool IsValid() const
{
return !!mIMC;
}
void SetOpenState(bool aOpen) const
{
if (!mIMC) {
return;
}
::ImmSetOpenStatus(mIMC, aOpen);
}
bool GetOpenState() const
{
if (!mIMC) {
return false;
}
return (::ImmGetOpenStatus(mIMC) != FALSE);
}
bool AssociateDefaultContext()
{
// We assume that there is only default IMC, no new IMC has been created.
if (mIMC) {
return false;
}
if (!::ImmAssociateContextEx(mWnd, nullptr, IACE_DEFAULT)) {
return false;
}
mIMC = ::ImmGetContext(mWnd);
return (mIMC != nullptr);
}
bool Disassociate()
{
if (!mIMC) {
return false;
}
if (!::ImmAssociateContextEx(mWnd, nullptr, 0)) {
return false;
}
::ImmReleaseContext(mWnd, mIMC);
mIMC = nullptr;
return true;
}
protected:
IMEContext(const IMEContext& aOther)
{
MOZ_CRASH("Don't copy IMEContext");
}
HWND mWnd;
HIMC mIMC;
};
class IMMHandler final
{
public:
static void Initialize();
static void Terminate();
// If Process*() returns true, the caller shouldn't do anything anymore.
static bool ProcessMessage(nsWindow* aWindow, UINT msg,
WPARAM& wParam, LPARAM& lParam,
MSGResult& aResult);
static bool IsComposing()
{
return IsComposingOnOurEditor();
}
static bool IsComposingOn(nsWindow* aWindow)
{
return IsComposing() && IsComposingWindow(aWindow);
}
#ifdef DEBUG
/**
* IsIMEAvailable() returns TRUE when current keyboard layout has IME.
* Otherwise, FALSE.
*/
static bool IsIMEAvailable() { return !!::ImmIsIME(::GetKeyboardLayout(0)); }
#endif
// If aForce is TRUE, these methods doesn't check whether we have composition
// or not. If you don't set it to TRUE, these method doesn't commit/cancel
// the composition on uexpected window.
static void CommitComposition(nsWindow* aWindow, bool aForce = false);
static void CancelComposition(nsWindow* aWindow, bool aForce = false);
static void OnFocusChange(bool aFocus, nsWindow* aWindow);
static void OnUpdateComposition(nsWindow* aWindow);
static void OnSelectionChange(nsWindow* aWindow,
const IMENotification& aIMENotification,
bool aIsIMMActive);
static nsIMEUpdatePreference GetIMEUpdatePreference();
// Returns NS_SUCCESS_EVENT_CONSUMED if the mouse button event is consumed by
// IME. Otherwise, NS_OK.
static nsresult OnMouseButtonEvent(nsWindow* aWindow,
const IMENotification& aIMENotification);
static void SetCandidateWindow(nsWindow* aWindow, CANDIDATEFORM* aForm);
static void DefaultProcOfPluginEvent(nsWindow* aWindow,
const NPEvent* aEvent);
protected:
static void EnsureHandlerInstance();
static bool IsComposingOnOurEditor();
static bool IsComposingOnPlugin();
static bool IsComposingWindow(nsWindow* aWindow);
static bool IsJapanist2003Active();
static bool IsGoogleJapaneseInputActive();
static bool ShouldDrawCompositionStringOurselves();
static bool IsVerticalWritingSupported();
// aWindow can be nullptr if it's called without receiving WM_INPUTLANGCHANGE.
static void InitKeyboardLayout(nsWindow* aWindow, HKL aKeyboardLayout);
static UINT GetKeyboardCodePage();
/**
* Checks whether the window is top level window of the composing window.
* In this method, the top level window means in all windows, not only in all
* OUR windows. I.e., if the aWindow is embedded, this always returns FALSE.
*/
static bool IsTopLevelWindowOfComposition(nsWindow* aWindow);
static bool ProcessInputLangChangeMessage(nsWindow* aWindow,
WPARAM wParam,
LPARAM lParam,
MSGResult& aResult);
static bool ProcessMessageForPlugin(nsWindow* aWindow, UINT msg,
WPARAM &wParam, LPARAM &lParam,
bool &aRet, MSGResult& aResult);
IMMHandler();
~IMMHandler();
// On*() methods return true if the caller of message handler shouldn't do
// anything anymore. Otherwise, false.
static bool OnKeyDownEvent(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
MSGResult& aResult);
bool OnIMEStartComposition(nsWindow* aWindow, MSGResult& aResult);
void OnIMEStartCompositionOnPlugin(nsWindow* aWindow,
WPARAM wParam, LPARAM lParam);
bool OnIMEComposition(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
MSGResult& aResult);
void OnIMECompositionOnPlugin(nsWindow* aWindow, WPARAM wParam,
LPARAM lParam);
bool OnIMEEndComposition(nsWindow* aWindow, MSGResult& aResult);
void OnIMEEndCompositionOnPlugin(nsWindow* aWindow, WPARAM wParam,
LPARAM lParam);
bool OnIMERequest(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
MSGResult& aResult);
bool OnIMECharOnPlugin(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
MSGResult& aResult);
bool OnChar(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
MSGResult& aResult);
bool OnCharOnPlugin(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
MSGResult& aResult);
void OnInputLangChange(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
MSGResult& aResult);
// These message handlers don't use instance members, we should not create
// the instance by the messages. So, they should be static.
static bool OnIMEChar(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
MSGResult& aResult);
static bool OnIMESetContext(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
MSGResult& aResult);
static bool OnIMESetContextOnPlugin(nsWindow* aWindow,
WPARAM wParam, LPARAM lParam,
MSGResult& aResult);
static bool OnIMECompositionFull(nsWindow* aWindow, MSGResult& aResult);
static bool OnIMENotify(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
MSGResult& aResult);
static bool OnIMESelect(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
MSGResult& aResult);
// The result of Handle* method mean "Processed" when it's TRUE.
void HandleStartComposition(nsWindow* aWindow,
const IMEContext& aContext);
bool HandleComposition(nsWindow* aWindow,
const IMEContext& aContext,
LPARAM lParam);
// If aCommitString is null, this commits composition with the latest
// dispatched data. Otherwise, commits composition with the value.
void HandleEndComposition(nsWindow* aWindow,
const nsAString* aCommitString = nullptr);
bool HandleReconvert(nsWindow* aWindow, LPARAM lParam, LRESULT *oResult);
bool HandleQueryCharPosition(nsWindow* aWindow, LPARAM lParam,
LRESULT *oResult);
bool HandleDocumentFeed(nsWindow* aWindow, LPARAM lParam, LRESULT *oResult);
/**
* When a window's IME context is activating but we have composition on
* another window, we should commit our composition because IME context is
* shared by all our windows (including plug-ins).
* @param aWindow is a new activated window.
* If aWindow is our composing window, this method does nothing.
* Otherwise, this commits the composition on the previous window.
* If this method did commit a composition, this returns TRUE.
*/
bool CommitCompositionOnPreviousWindow(nsWindow* aWindow);
/**
* ResolveIMECaretPos
* Convert the caret rect of a composition event to another widget's
* coordinate system.
*
* @param aReferenceWidget The origin widget of aCursorRect.
* Typically, this is mReferenceWidget of the
* composing events. If the aCursorRect is in screen
* coordinates, set nullptr.
* @param aCursorRect The cursor rect.
* @param aNewOriginWidget aOutRect will be in this widget's coordinates. If
* this is nullptr, aOutRect will be in screen
* coordinates.
* @param aOutRect The converted cursor rect.
*/
void ResolveIMECaretPos(nsIWidget* aReferenceWidget,
mozilla::LayoutDeviceIntRect& aCursorRect,
nsIWidget* aNewOriginWidget,
mozilla::LayoutDeviceIntRect& aOutRect);
bool ConvertToANSIString(const nsAFlatString& aStr,
UINT aCodePage,
nsACString& aANSIStr);
bool SetIMERelatedWindowsPos(nsWindow* aWindow,
const IMEContext& aContext);
void SetIMERelatedWindowsPosOnPlugin(nsWindow* aWindow,
const IMEContext& aContext);
/**
* GetCharacterRectOfSelectedTextAt() returns character rect of the offset
* from the selection start or the start of composition string if there is
* a composition.
*
* @param aWindow The window which has focus.
* @param aOffset Offset from the selection start or the start of
* composition string when there is a composition.
* This must be in the selection range or
* the composition string.
* @param aCharRect The result.
* @param aWritingMode The writing mode of current selection. When this
* is nullptr, this assumes that the selection is in
* horizontal writing mode.
* @return true if this succeeded to retrieve the rect.
* Otherwise, false.
*/
bool GetCharacterRectOfSelectedTextAt(
nsWindow* aWindow,
uint32_t aOffset,
mozilla::LayoutDeviceIntRect& aCharRect,
mozilla::WritingMode* aWritingMode = nullptr);
/**
* GetCaretRect() returns caret rect at current selection start.
*
* @param aWindow The window which has focus.
* @param aCaretRect The result.
* @param aWritingMode The writing mode of current selection. When this
* is nullptr, this assumes that the selection is in
* horizontal writing mode.
* @return true if this succeeded to retrieve the rect.
* Otherwise, false.
*/
bool GetCaretRect(nsWindow* aWindow,
mozilla::LayoutDeviceIntRect& aCaretRect,
mozilla::WritingMode* aWritingMode = nullptr);
void GetCompositionString(const IMEContext& aContext,
DWORD aIndex,
nsAString& aCompositionString) const;
/**
* AdjustCompositionFont() makes IME vertical writing mode if it's supported.
* If aForceUpdate is true, it will update composition font even if writing
* mode isn't being changed.
*/
void AdjustCompositionFont(nsWindow* aWindow,
const IMEContext& aContext,
const mozilla::WritingMode& aWritingMode,
bool aForceUpdate = false);
/**
* MaybeAdjustCompositionFont() calls AdjustCompositionFont() when the
* locale of active IME is CJK. Note that this creates an instance even
* when there is no composition but the locale is CJK.
*/
static void MaybeAdjustCompositionFont(
nsWindow* aWindow,
const mozilla::WritingMode& aWritingMode,
bool aForceUpdate = false);
/**
* Get the current target clause of composition string.
* If there are one or more characters whose attribute is ATTR_TARGET_*,
* this returns the first character's offset and its length.
* Otherwise, e.g., the all characters are ATTR_INPUT, this returns
* the composition string range because the all is the current target.
*
* aLength can be null (default), but aOffset must not be null.
*
* The aOffset value is offset in the contents. So, when you need offset
* in the composition string, you need to subtract mCompositionStart from it.
*/
bool GetTargetClauseRange(uint32_t *aOffset, uint32_t *aLength = nullptr);
/**
* DispatchEvent() dispatches aEvent if aWidget hasn't been destroyed yet.
*/
static void DispatchEvent(nsWindow* aWindow, WidgetGUIEvent& aEvent);
/**
* DispatchCompositionChangeEvent() dispatches eCompositionChange event
* with clause information (it'll be retrieved by CreateTextRangeArray()).
* I.e., this should be called only during composing. If a composition is
* being committed, only HandleCompositionEnd() should be called.
*
* @param aWindow The window which has the composition.
* @param aContext Native IME context which has the composition.
*/
void DispatchCompositionChangeEvent(nsWindow* aWindow,
const IMEContext& aContext);
nsresult EnsureClauseArray(int32_t aCount);
nsresult EnsureAttributeArray(int32_t aCount);
/**
* When WM_IME_CHAR is received and passed to DefWindowProc, we need to
* record the messages. In other words, we should record the messages
* when we receive WM_IME_CHAR on windowless plug-in (if we have focus,
* we always eat them). When focus is moved from a windowless plug-in to
* our window during composition, WM_IME_CHAR messages were received when
* the plug-in has focus. However, WM_CHAR messages are received after the
* plug-in lost focus. So, we need to ignore the WM_CHAR messages because
* they make unexpected text input events on us.
*/
nsTArray<MSG> mPassedIMEChar;
bool IsIMECharRecordsEmpty()
{
return mPassedIMEChar.IsEmpty();
}
void ResetIMECharRecords()
{
mPassedIMEChar.Clear();
}
void DequeueIMECharRecords(WPARAM &wParam, LPARAM &lParam)
{
MSG msg = mPassedIMEChar.ElementAt(0);
wParam = msg.wParam;
lParam = msg.lParam;
mPassedIMEChar.RemoveElementAt(0);
}
void EnqueueIMECharRecords(WPARAM wParam, LPARAM lParam)
{
MSG msg;
msg.wParam = wParam;
msg.lParam = lParam;
mPassedIMEChar.AppendElement(msg);
}
TextEventDispatcher* GetTextEventDispatcherFor(nsWindow* aWindow);
nsWindow* mComposingWindow;
RefPtr<TextEventDispatcher> mDispatcher;
nsString mCompositionString;
InfallibleTArray<uint32_t> mClauseArray;
InfallibleTArray<uint8_t> mAttributeArray;
int32_t mCursorPosition;
uint32_t mCompositionStart;
struct Selection
{
nsString mString;
uint32_t mOffset;
mozilla::WritingMode mWritingMode;
bool mIsValid;
Selection()
: mOffset(UINT32_MAX)
, mIsValid(false)
{
}
void Clear()
{
mOffset = UINT32_MAX;
mIsValid = false;
}
uint32_t Length() const { return mString.Length(); }
bool Collapsed() const { return !Length(); }
bool IsValid() const;
bool Update(const IMENotification& aIMENotification);
bool Init(nsWindow* aWindow);
bool EnsureValidSelection(nsWindow* aWindow);
private:
Selection(const Selection& aOther) = delete;
void operator =(const Selection& aOther) = delete;
};
// mSelection stores the latest selection data only when sHasFocus is true.
// Don't access mSelection directly. You should use GetSelection() for
// getting proper state.
Selection mSelection;
Selection& GetSelection()
{
// When IME has focus, mSelection is automatically updated by
// NOTIFY_IME_OF_SELECTION_CHANGE.
if (sHasFocus) {
return mSelection;
}
// Otherwise, i.e., While IME doesn't have focus, we cannot observe
// selection changes. So, in such case, we need to query selection
// when it's necessary.
static Selection sTempSelection;
sTempSelection.Clear();
return sTempSelection;
}
bool mIsComposing;
bool mIsComposingOnPlugin;
bool mNativeCaretIsCreated;
static mozilla::WritingMode sWritingModeOfCompositionFont;
static nsString sIMEName;
static UINT sCodePage;
static DWORD sIMEProperty;
static DWORD sIMEUIProperty;
static bool sAssumeVerticalWritingModeNotSupported;
static bool sHasFocus;
static bool sNativeCaretIsCreatedForPlugin;
};
} // namespace widget
} // namespace mozilla
#endif // IMMHandler_h_

View file

@ -0,0 +1,41 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "InProcessWinCompositorWidget.h"
#include "nsWindow.h"
namespace mozilla {
namespace widget {
/* static */ RefPtr<CompositorWidget>
CompositorWidget::CreateLocal(const CompositorWidgetInitData& aInitData, nsIWidget* aWidget)
{
return new InProcessWinCompositorWidget(aInitData, static_cast<nsWindow*>(aWidget));
}
InProcessWinCompositorWidget::InProcessWinCompositorWidget(const CompositorWidgetInitData& aInitData,
nsWindow* aWindow)
: WinCompositorWidget(aInitData),
mWindow(aWindow)
{
MOZ_ASSERT(mWindow);
}
nsIWidget*
InProcessWinCompositorWidget::RealWidget()
{
return mWindow;
}
void
InProcessWinCompositorWidget::ObserveVsync(VsyncObserver* aObserver)
{
if (RefPtr<CompositorVsyncDispatcher> cvd = mWindow->GetCompositorVsyncDispatcher()) {
cvd->SetCompositorVsyncObserver(aObserver);
}
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,35 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef widget_windows_InProcessCompositorWidgetParent_h
#define widget_windows_InProcessCompositorWidgetParent_h
#include "WinCompositorWidget.h"
class nsWindow;
namespace mozilla {
namespace widget {
// This is the Windows-specific implementation of CompositorWidget. For
// the most part it only requires an HWND, however it maintains extra state
// for transparent windows, as well as for synchronizing WM_SETTEXT messages
// with the compositor.
class InProcessWinCompositorWidget final : public WinCompositorWidget
{
public:
InProcessWinCompositorWidget(const CompositorWidgetInitData& aInitData, nsWindow* aWindow);
void ObserveVsync(VsyncObserver* aObserver) override;
nsIWidget* RealWidget() override;
private:
nsWindow* mWindow;
};
} // namespace widget
} // namespace mozilla
#endif // widget_windows_InProcessCompositorWidgetParent_h

View file

@ -0,0 +1,253 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=2 sw=2 et tw=78:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "InkCollector.h"
// Msinkaut_i.c and Msinkaut.h should both be included
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms695519.aspx
#include <msinkaut_i.c>
StaticAutoPtr<InkCollector> InkCollector::sInkCollector;
InkCollector::~InkCollector()
{
Shutdown();
MOZ_ASSERT(!mCookie && !mEnabled && !mComInitialized
&& !mMarshaller && !mInkCollector
&& !mConnectionPoint && !mInkCollectorEvent);
}
void InkCollector::Initialize()
{
// Possibly, we can use mConnectionPoint for checking,
// But if errors exist (perhaps COM object is unavailable),
// Initialize() will be called more times.
static bool sInkCollectorCreated = false;
if (sInkCollectorCreated) {
return;
}
sInkCollectorCreated = true;
// COM could get uninitialized due to previous initialization.
mComInitialized = SUCCEEDED(::CoInitialize(nullptr));
// Set up instance of InkCollectorEvent.
mInkCollectorEvent = new InkCollectorEvent();
// Set up a free threaded marshaler.
if (FAILED(::CoCreateFreeThreadedMarshaler(mInkCollectorEvent, getter_AddRefs(mMarshaller)))) {
return;
}
// Create the ink collector.
if (FAILED(::CoCreateInstance(CLSID_InkCollector, NULL, CLSCTX_INPROC_SERVER,
IID_IInkCollector, getter_AddRefs(mInkCollector)))) {
return;
}
// Set up connection between sink and InkCollector.
RefPtr<IConnectionPointContainer> connPointContainer;
// Get the connection point container.
if (SUCCEEDED(mInkCollector->QueryInterface(IID_IConnectionPointContainer,
getter_AddRefs(connPointContainer)))) {
// Find the connection point for Ink Collector events.
if (SUCCEEDED(connPointContainer->FindConnectionPoint(__uuidof(_IInkCollectorEvents),
getter_AddRefs(mConnectionPoint)))) {
// Hook up sink to connection point.
if (SUCCEEDED(mConnectionPoint->Advise(mInkCollectorEvent, &mCookie))) {
OnInitialize();
}
}
}
}
void InkCollector::Shutdown()
{
Enable(false);
if (mConnectionPoint) {
// Remove the connection of the sink to the Ink Collector.
mConnectionPoint->Unadvise(mCookie);
mCookie = 0;
mConnectionPoint = nullptr;
}
mInkCollector = nullptr;
mMarshaller = nullptr;
mInkCollectorEvent = nullptr;
// Let uninitialization get handled in a place where it got inited.
if (mComInitialized) {
CoUninitialize();
mComInitialized = false;
}
}
void InkCollector::OnInitialize()
{
// Suppress all events to do not allow performance decreasing.
// https://msdn.microsoft.com/en-us/library/ms820347.aspx
mInkCollector->SetEventInterest(InkCollectorEventInterest::ICEI_AllEvents, VARIANT_FALSE);
// Sets a value that indicates whether an object or control has interest in a specified event.
mInkCollector->SetEventInterest(InkCollectorEventInterest::ICEI_CursorOutOfRange, VARIANT_TRUE);
// If the MousePointer property is set to IMP_Custom and the MouseIcon property is NULL,
// Then the ink collector no longer handles mouse cursor settings.
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms700686.aspx
mInkCollector->put_MouseIcon(nullptr);
mInkCollector->put_MousePointer(InkMousePointer::IMP_Custom);
// This mode allows an ink collector to collect ink from any tablet attached to the Tablet PC.
// The Boolean value that indicates whether to use the mouse as an input device.
// If TRUE, the mouse is used for input.
// https://msdn.microsoft.com/en-us/library/ms820346.aspx
mInkCollector->SetAllTabletsMode(VARIANT_FALSE);
// Sets the value that specifies whether ink is rendered as it is drawn.
// VARIANT_TRUE to render ink as it is drawn on the display.
// VARIANT_FALSE to not have the ink appear on the display as strokes are made.
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd314598.aspx
mInkCollector->put_DynamicRendering(VARIANT_FALSE);
}
// Sets a value that specifies whether the InkCollector object collects pen input.
// This property must be set to FALSE before setting or
// calling specific properties and methods of the object.
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms701721.aspx
void InkCollector::Enable(bool aNewState)
{
if (aNewState != mEnabled) {
if (mInkCollector) {
if (SUCCEEDED(mInkCollector->put_Enabled(aNewState ? VARIANT_TRUE : VARIANT_FALSE))) {
mEnabled = aNewState;
} else {
NS_WARNING("InkCollector did not change status successfully");
}
} else {
NS_WARNING("InkCollector should be exist");
}
}
}
HWND InkCollector::GetTarget()
{
return mTargetWindow;
}
void InkCollector::SetTarget(HWND aTargetWindow)
{
NS_ASSERTION(aTargetWindow, "aTargetWindow should be exist");
if (aTargetWindow && (aTargetWindow != mTargetWindow)) {
Initialize();
if (mInkCollector) {
Enable(false);
if (SUCCEEDED(mInkCollector->put_hWnd((LONG_PTR)aTargetWindow))) {
mTargetWindow = aTargetWindow;
} else {
NS_WARNING("InkCollector did not change window property successfully");
}
Enable(true);
}
}
}
void InkCollector::ClearTarget()
{
if (mTargetWindow && mInkCollector) {
Enable(false);
if (SUCCEEDED(mInkCollector->put_hWnd(0))) {
mTargetWindow = 0;
} else {
NS_WARNING("InkCollector did not clear window property successfully");
}
}
}
uint16_t InkCollector::GetPointerId()
{
return mPointerId;
}
void InkCollector::SetPointerId(uint16_t aPointerId)
{
mPointerId = aPointerId;
}
void InkCollector::ClearPointerId()
{
mPointerId = 0;
}
// The display and the digitizer have quite different properties.
// The display has CursorMustTouch, the mouse pointer alway touches the display surface.
// The digitizer lists Integrated and HardProximity.
// When the stylus is in the proximity of the tablet its movements are also detected.
// An external tablet will only list HardProximity.
bool InkCollectorEvent::IsHardProximityTablet(IInkTablet* aTablet) const
{
if (aTablet) {
TabletHardwareCapabilities caps;
if (SUCCEEDED(aTablet->get_HardwareCapabilities(&caps))) {
return (TabletHardwareCapabilities::THWC_HardProximity & caps);
}
}
return false;
}
HRESULT __stdcall InkCollectorEvent::QueryInterface(REFIID aRiid, void **aObject)
{
// Validate the input
if (!aObject) {
return E_POINTER;
}
HRESULT result = E_NOINTERFACE;
// This object supports IUnknown/IDispatch/IInkCollectorEvents
if ((IID_IUnknown == aRiid) ||
(IID_IDispatch == aRiid) ||
(DIID__IInkCollectorEvents == aRiid)) {
*aObject = this;
// AddRef should be called when we give info about interface
NS_ADDREF_THIS();
result = S_OK;
}
return result;
}
HRESULT InkCollectorEvent::Invoke(DISPID aDispIdMember, REFIID /*aRiid*/,
LCID /*aId*/, WORD /*wFlags*/,
DISPPARAMS* aDispParams, VARIANT* /*aVarResult*/,
EXCEPINFO* /*aExcepInfo*/, UINT* /*aArgErr*/)
{
switch (aDispIdMember) {
case DISPID_ICECursorOutOfRange: {
if (aDispParams && aDispParams->cArgs) {
CursorOutOfRange(static_cast<IInkCursor*>(aDispParams->rgvarg[0].pdispVal));
}
break;
}
}
return S_OK;
}
void InkCollectorEvent::CursorOutOfRange(IInkCursor* aCursor) const
{
IInkTablet* curTablet = nullptr;
if (FAILED(aCursor->get_Tablet(&curTablet))) {
return;
}
// All events should be suppressed except
// from tablets with hard proximity.
if (!IsHardProximityTablet(curTablet)) {
return;
}
// Notify current target window.
if (HWND targetWindow = InkCollector::sInkCollector->GetTarget()) {
::SendMessage(targetWindow, MOZ_WM_PEN_LEAVES_HOVER_OF_DIGITIZER, 0, 0);
}
}

View file

@ -0,0 +1,98 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=2 sw=2 et tw=78:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef InkCollector_h__
#define InkCollector_h__
#include <msinkaut.h>
#include "mozilla/StaticPtr.h"
#define MOZ_WM_PEN_LEAVES_HOVER_OF_DIGITIZER WM_USER + 0x83
class InkCollectorEvent : public _IInkCollectorEvents
{
public:
// IUnknown
HRESULT __stdcall QueryInterface(REFIID aRiid, void **aObject);
virtual ULONG STDMETHODCALLTYPE AddRef() { return ++mRefCount; }
virtual ULONG STDMETHODCALLTYPE Release()
{
MOZ_ASSERT(mRefCount);
if (!--mRefCount) {
delete this;
return 0;
}
return mRefCount;
}
protected:
// IDispatch
STDMETHOD(GetTypeInfoCount)(UINT* aInfo) { return E_NOTIMPL; }
STDMETHOD(GetTypeInfo)(UINT aInfo, LCID aId, ITypeInfo** aTInfo) { return E_NOTIMPL; }
STDMETHOD(GetIDsOfNames)(REFIID aRiid, LPOLESTR* aStrNames, UINT aNames,
LCID aId, DISPID* aDispId) { return E_NOTIMPL; }
STDMETHOD(Invoke)(DISPID aDispIdMember, REFIID aRiid,
LCID aId, WORD wFlags,
DISPPARAMS* aDispParams, VARIANT* aVarResult,
EXCEPINFO* aExcepInfo, UINT* aArgErr);
// InkCollectorEvent
void CursorOutOfRange(IInkCursor* aCursor) const;
bool IsHardProximityTablet(IInkTablet* aTablet) const;
private:
uint32_t mRefCount = 0;
};
class InkCollector
{
public:
~InkCollector();
void Shutdown();
HWND GetTarget();
void SetTarget(HWND aTargetWindow);
void ClearTarget();
uint16_t GetPointerId(); // 0 shows that there is no existing pen.
void SetPointerId(uint16_t aPointerId);
void ClearPointerId();
static StaticAutoPtr<InkCollector> sInkCollector;
protected:
void Initialize();
void OnInitialize();
void Enable(bool aNewState);
private:
RefPtr<IUnknown> mMarshaller;
RefPtr<IInkCollector> mInkCollector;
RefPtr<IConnectionPoint> mConnectionPoint;
RefPtr<InkCollectorEvent> mInkCollectorEvent;
HWND mTargetWindow = 0;
DWORD mCookie = 0;
bool mComInitialized = false;
bool mEnabled = false;
// This value holds the previous pointerId of the pen, and is used by the
// nsWindow when processing a MOZ_WM_PEN_LEAVES_HOVER_OF_DIGITIZER which
// indicates that a pen leaves the digitizer.
// TODO: If we move our implementation to window pointer input messages, then
// we no longer need this value, since the pointerId can be retrieved from the
// window message, please refer to
// https://msdn.microsoft.com/en-us/library/windows/desktop/hh454916(v=vs.85).aspx
// NOTE: The pointerId of a pen shouldn't be 0 on a Windows platform, since 0
// is reserved of the mouse, please refer to
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms703320(v=vs.85).aspx
uint16_t mPointerId = 0;
};
#endif // InkCollector_h__

View file

@ -0,0 +1,542 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "JumpListBuilder.h"
#include "nsError.h"
#include "nsCOMPtr.h"
#include "nsServiceManagerUtils.h"
#include "nsString.h"
#include "nsArrayUtils.h"
#include "nsIMutableArray.h"
#include "nsWidgetsCID.h"
#include "WinTaskbar.h"
#include "nsDirectoryServiceUtils.h"
#include "nsISimpleEnumerator.h"
#include "mozilla/Preferences.h"
#include "nsStringStream.h"
#include "nsThreadUtils.h"
#include "mozilla/LazyIdleThread.h"
#include "nsIObserverService.h"
#include "WinUtils.h"
// The amount of time, in milliseconds, that our IO thread will stay alive after the last event it processes.
#define DEFAULT_THREAD_TIMEOUT_MS 30000
namespace mozilla {
namespace widget {
static NS_DEFINE_CID(kJumpListItemCID, NS_WIN_JUMPLISTITEM_CID);
static NS_DEFINE_CID(kJumpListLinkCID, NS_WIN_JUMPLISTLINK_CID);
static NS_DEFINE_CID(kJumpListShortcutCID, NS_WIN_JUMPLISTSHORTCUT_CID);
// defined in WinTaskbar.cpp
extern const wchar_t *gMozillaJumpListIDGeneric;
bool JumpListBuilder::sBuildingList = false;
const char kPrefTaskbarEnabled[] = "browser.taskbar.lists.enabled";
NS_IMPL_ISUPPORTS(JumpListBuilder, nsIJumpListBuilder, nsIObserver)
#define TOPIC_PROFILE_BEFORE_CHANGE "profile-before-change"
#define TOPIC_CLEAR_PRIVATE_DATA "clear-private-data"
JumpListBuilder::JumpListBuilder() :
mMaxItems(0),
mHasCommit(false)
{
::CoInitialize(nullptr);
CoCreateInstance(CLSID_DestinationList, nullptr, CLSCTX_INPROC_SERVER,
IID_ICustomDestinationList, getter_AddRefs(mJumpListMgr));
// Make a lazy thread for any IO
mIOThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
NS_LITERAL_CSTRING("Jump List"),
LazyIdleThread::ManualShutdown);
Preferences::AddStrongObserver(this, kPrefTaskbarEnabled);
nsCOMPtr<nsIObserverService> observerService =
do_GetService("@mozilla.org/observer-service;1");
if (observerService) {
observerService->AddObserver(this, TOPIC_PROFILE_BEFORE_CHANGE, false);
observerService->AddObserver(this, TOPIC_CLEAR_PRIVATE_DATA, false);
}
}
JumpListBuilder::~JumpListBuilder()
{
Preferences::RemoveObserver(this, kPrefTaskbarEnabled);
mJumpListMgr = nullptr;
::CoUninitialize();
}
NS_IMETHODIMP JumpListBuilder::GetAvailable(int16_t *aAvailable)
{
*aAvailable = false;
if (mJumpListMgr)
*aAvailable = true;
return NS_OK;
}
NS_IMETHODIMP JumpListBuilder::GetIsListCommitted(bool *aCommit)
{
*aCommit = mHasCommit;
return NS_OK;
}
NS_IMETHODIMP JumpListBuilder::GetMaxListItems(int16_t *aMaxItems)
{
if (!mJumpListMgr)
return NS_ERROR_NOT_AVAILABLE;
*aMaxItems = 0;
if (sBuildingList) {
*aMaxItems = mMaxItems;
return NS_OK;
}
IObjectArray *objArray;
if (SUCCEEDED(mJumpListMgr->BeginList(&mMaxItems, IID_PPV_ARGS(&objArray)))) {
*aMaxItems = mMaxItems;
if (objArray)
objArray->Release();
mJumpListMgr->AbortList();
}
return NS_OK;
}
NS_IMETHODIMP JumpListBuilder::InitListBuild(nsIMutableArray *removedItems, bool *_retval)
{
NS_ENSURE_ARG_POINTER(removedItems);
*_retval = false;
if (!mJumpListMgr)
return NS_ERROR_NOT_AVAILABLE;
if(sBuildingList)
AbortListBuild();
IObjectArray *objArray;
// The returned objArray of removed items are for manually removed items.
// This does not return items which are removed because they were previously
// part of the jump list but are no longer part of the jump list.
if (SUCCEEDED(mJumpListMgr->BeginList(&mMaxItems, IID_PPV_ARGS(&objArray)))) {
if (objArray) {
TransferIObjectArrayToIMutableArray(objArray, removedItems);
objArray->Release();
}
RemoveIconCacheForItems(removedItems);
sBuildingList = true;
*_retval = true;
return NS_OK;
}
return NS_OK;
}
// Ensures that we don't have old ICO files that aren't in our jump lists
// anymore left over in the cache.
nsresult JumpListBuilder::RemoveIconCacheForItems(nsIMutableArray *items)
{
NS_ENSURE_ARG_POINTER(items);
nsresult rv;
uint32_t length;
items->GetLength(&length);
for (uint32_t i = 0; i < length; ++i) {
//Obtain an IJumpListItem and get the type
nsCOMPtr<nsIJumpListItem> item = do_QueryElementAt(items, i);
if (!item) {
continue;
}
int16_t type;
if (NS_FAILED(item->GetType(&type))) {
continue;
}
// If the item is a shortcut, remove its associated icon if any
if (type == nsIJumpListItem::JUMPLIST_ITEM_SHORTCUT) {
nsCOMPtr<nsIJumpListShortcut> shortcut = do_QueryInterface(item);
if (shortcut) {
nsCOMPtr<nsIURI> uri;
rv = shortcut->GetFaviconPageUri(getter_AddRefs(uri));
if (NS_SUCCEEDED(rv) && uri) {
// The local file path is stored inside the nsIURI
// Get the nsIURI spec which stores the local path for the icon to remove
nsAutoCString spec;
nsresult rv = uri->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIRunnable> event
= new mozilla::widget::AsyncDeleteIconFromDisk(NS_ConvertUTF8toUTF16(spec));
mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
// The shortcut was generated from an IShellLinkW so IShellLinkW can
// only tell us what the original icon is and not the URI.
// So this field was used only temporarily as the actual icon file
// path. It should be cleared.
shortcut->SetFaviconPageUri(nullptr);
}
}
}
} // end for
return NS_OK;
}
// Ensures that we have no old ICO files left in the jump list cache
nsresult JumpListBuilder::RemoveIconCacheForAllItems()
{
// Construct the path of our jump list cache
nsCOMPtr<nsIFile> jumpListCacheDir;
nsresult rv = NS_GetSpecialDirectory("ProfLDS",
getter_AddRefs(jumpListCacheDir));
NS_ENSURE_SUCCESS(rv, rv);
rv = jumpListCacheDir->AppendNative(nsDependentCString(
mozilla::widget::FaviconHelper::kJumpListCacheDir));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISimpleEnumerator> entries;
rv = jumpListCacheDir->GetDirectoryEntries(getter_AddRefs(entries));
NS_ENSURE_SUCCESS(rv, rv);
// Loop through each directory entry and remove all ICO files found
do {
bool hasMore = false;
if (NS_FAILED(entries->HasMoreElements(&hasMore)) || !hasMore)
break;
nsCOMPtr<nsISupports> supp;
if (NS_FAILED(entries->GetNext(getter_AddRefs(supp))))
break;
nsCOMPtr<nsIFile> currFile(do_QueryInterface(supp));
nsAutoString path;
if (NS_FAILED(currFile->GetPath(path)))
continue;
if (StringTail(path, 4).LowerCaseEqualsASCII(".ico")) {
// Check if the cached ICO file exists
bool exists;
if (NS_FAILED(currFile->Exists(&exists)) || !exists)
continue;
// We found an ICO file that exists, so we should remove it
currFile->Remove(false);
}
} while(true);
return NS_OK;
}
NS_IMETHODIMP JumpListBuilder::AddListToBuild(int16_t aCatType, nsIArray *items, const nsAString &catName, bool *_retval)
{
nsresult rv;
*_retval = false;
if (!mJumpListMgr)
return NS_ERROR_NOT_AVAILABLE;
switch(aCatType) {
case nsIJumpListBuilder::JUMPLIST_CATEGORY_TASKS:
{
NS_ENSURE_ARG_POINTER(items);
HRESULT hr;
RefPtr<IObjectCollection> collection;
hr = CoCreateInstance(CLSID_EnumerableObjectCollection, nullptr,
CLSCTX_INPROC_SERVER, IID_IObjectCollection,
getter_AddRefs(collection));
if (FAILED(hr))
return NS_ERROR_UNEXPECTED;
// Build the list
uint32_t length;
items->GetLength(&length);
for (uint32_t i = 0; i < length; ++i) {
nsCOMPtr<nsIJumpListItem> item = do_QueryElementAt(items, i);
if (!item)
continue;
// Check for separators
if (IsSeparator(item)) {
RefPtr<IShellLinkW> link;
rv = JumpListSeparator::GetSeparator(link);
if (NS_FAILED(rv))
return rv;
collection->AddObject(link);
continue;
}
// These should all be ShellLinks
RefPtr<IShellLinkW> link;
rv = JumpListShortcut::GetShellLink(item, link, mIOThread);
if (NS_FAILED(rv))
return rv;
collection->AddObject(link);
}
// We need IObjectArray to submit
RefPtr<IObjectArray> pArray;
hr = collection->QueryInterface(IID_IObjectArray, getter_AddRefs(pArray));
if (FAILED(hr))
return NS_ERROR_UNEXPECTED;
// Add the tasks
hr = mJumpListMgr->AddUserTasks(pArray);
if (SUCCEEDED(hr))
*_retval = true;
return NS_OK;
}
break;
case nsIJumpListBuilder::JUMPLIST_CATEGORY_RECENT:
{
if (SUCCEEDED(mJumpListMgr->AppendKnownCategory(KDC_RECENT)))
*_retval = true;
return NS_OK;
}
break;
case nsIJumpListBuilder::JUMPLIST_CATEGORY_FREQUENT:
{
if (SUCCEEDED(mJumpListMgr->AppendKnownCategory(KDC_FREQUENT)))
*_retval = true;
return NS_OK;
}
break;
case nsIJumpListBuilder::JUMPLIST_CATEGORY_CUSTOMLIST:
{
NS_ENSURE_ARG_POINTER(items);
if (catName.IsEmpty())
return NS_ERROR_INVALID_ARG;
HRESULT hr;
RefPtr<IObjectCollection> collection;
hr = CoCreateInstance(CLSID_EnumerableObjectCollection, nullptr,
CLSCTX_INPROC_SERVER, IID_IObjectCollection,
getter_AddRefs(collection));
if (FAILED(hr))
return NS_ERROR_UNEXPECTED;
uint32_t length;
items->GetLength(&length);
for (uint32_t i = 0; i < length; ++i) {
nsCOMPtr<nsIJumpListItem> item = do_QueryElementAt(items, i);
if (!item)
continue;
int16_t type;
if (NS_FAILED(item->GetType(&type)))
continue;
switch(type) {
case nsIJumpListItem::JUMPLIST_ITEM_SEPARATOR:
{
RefPtr<IShellLinkW> shellItem;
rv = JumpListSeparator::GetSeparator(shellItem);
if (NS_FAILED(rv))
return rv;
collection->AddObject(shellItem);
}
break;
case nsIJumpListItem::JUMPLIST_ITEM_LINK:
{
RefPtr<IShellItem2> shellItem;
rv = JumpListLink::GetShellItem(item, shellItem);
if (NS_FAILED(rv))
return rv;
collection->AddObject(shellItem);
}
break;
case nsIJumpListItem::JUMPLIST_ITEM_SHORTCUT:
{
RefPtr<IShellLinkW> shellItem;
rv = JumpListShortcut::GetShellLink(item, shellItem, mIOThread);
if (NS_FAILED(rv))
return rv;
collection->AddObject(shellItem);
}
break;
}
}
// We need IObjectArray to submit
RefPtr<IObjectArray> pArray;
hr = collection->QueryInterface(IID_IObjectArray, (LPVOID*)&pArray);
if (FAILED(hr))
return NS_ERROR_UNEXPECTED;
// Add the tasks
hr = mJumpListMgr->AppendCategory(reinterpret_cast<const wchar_t*>(catName.BeginReading()), pArray);
if (SUCCEEDED(hr))
*_retval = true;
// Get rid of the old icons
nsCOMPtr<nsIRunnable> event =
new mozilla::widget::AsyncDeleteAllFaviconsFromDisk(true);
mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
return NS_OK;
}
break;
}
return NS_OK;
}
NS_IMETHODIMP JumpListBuilder::AbortListBuild()
{
if (!mJumpListMgr)
return NS_ERROR_NOT_AVAILABLE;
mJumpListMgr->AbortList();
sBuildingList = false;
return NS_OK;
}
NS_IMETHODIMP JumpListBuilder::CommitListBuild(bool *_retval)
{
*_retval = false;
if (!mJumpListMgr)
return NS_ERROR_NOT_AVAILABLE;
HRESULT hr = mJumpListMgr->CommitList();
sBuildingList = false;
// XXX We might want some specific error data here.
if (SUCCEEDED(hr)) {
*_retval = true;
mHasCommit = true;
}
return NS_OK;
}
NS_IMETHODIMP JumpListBuilder::DeleteActiveList(bool *_retval)
{
*_retval = false;
if (!mJumpListMgr)
return NS_ERROR_NOT_AVAILABLE;
if(sBuildingList)
AbortListBuild();
nsAutoString uid;
if (!WinTaskbar::GetAppUserModelID(uid))
return NS_OK;
if (SUCCEEDED(mJumpListMgr->DeleteList(uid.get())))
*_retval = true;
return NS_OK;
}
/* internal */
bool JumpListBuilder::IsSeparator(nsCOMPtr<nsIJumpListItem>& item)
{
int16_t type;
item->GetType(&type);
if (NS_FAILED(item->GetType(&type)))
return false;
if (type == nsIJumpListItem::JUMPLIST_ITEM_SEPARATOR)
return true;
return false;
}
// TransferIObjectArrayToIMutableArray - used in converting removed items
// to our objects.
nsresult JumpListBuilder::TransferIObjectArrayToIMutableArray(IObjectArray *objArray, nsIMutableArray *removedItems)
{
NS_ENSURE_ARG_POINTER(objArray);
NS_ENSURE_ARG_POINTER(removedItems);
nsresult rv;
uint32_t count = 0;
objArray->GetCount(&count);
nsCOMPtr<nsIJumpListItem> item;
for (uint32_t idx = 0; idx < count; idx++) {
IShellLinkW * pLink = nullptr;
IShellItem * pItem = nullptr;
if (SUCCEEDED(objArray->GetAt(idx, IID_IShellLinkW, (LPVOID*)&pLink))) {
nsCOMPtr<nsIJumpListShortcut> shortcut =
do_CreateInstance(kJumpListShortcutCID, &rv);
if (NS_FAILED(rv))
return NS_ERROR_UNEXPECTED;
rv = JumpListShortcut::GetJumpListShortcut(pLink, shortcut);
item = do_QueryInterface(shortcut);
}
else if (SUCCEEDED(objArray->GetAt(idx, IID_IShellItem, (LPVOID*)&pItem))) {
nsCOMPtr<nsIJumpListLink> link =
do_CreateInstance(kJumpListLinkCID, &rv);
if (NS_FAILED(rv))
return NS_ERROR_UNEXPECTED;
rv = JumpListLink::GetJumpListLink(pItem, link);
item = do_QueryInterface(link);
}
if (pLink)
pLink->Release();
if (pItem)
pItem->Release();
if (NS_SUCCEEDED(rv)) {
removedItems->AppendElement(item, false);
}
}
return NS_OK;
}
NS_IMETHODIMP JumpListBuilder::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
NS_ENSURE_ARG_POINTER(aTopic);
if (strcmp(aTopic, TOPIC_PROFILE_BEFORE_CHANGE) == 0) {
nsCOMPtr<nsIObserverService> observerService =
do_GetService("@mozilla.org/observer-service;1");
if (observerService) {
observerService->RemoveObserver(this, TOPIC_PROFILE_BEFORE_CHANGE);
}
mIOThread->Shutdown();
} else if (strcmp(aTopic, "nsPref:changed") == 0 &&
nsDependentString(aData).EqualsASCII(kPrefTaskbarEnabled)) {
bool enabled = Preferences::GetBool(kPrefTaskbarEnabled, true);
if (!enabled) {
nsCOMPtr<nsIRunnable> event =
new mozilla::widget::AsyncDeleteAllFaviconsFromDisk();
mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
}
} else if (strcmp(aTopic, TOPIC_CLEAR_PRIVATE_DATA) == 0) {
// Delete JumpListCache icons from Disk, if any.
nsCOMPtr<nsIRunnable> event =
new mozilla::widget::AsyncDeleteAllFaviconsFromDisk(false);
mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
}
return NS_OK;
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __JumpListBuilder_h__
#define __JumpListBuilder_h__
#include <windows.h>
#undef NTDDI_VERSION
#define NTDDI_VERSION NTDDI_WIN7
// Needed for various com interfaces
#include <shobjidl.h>
#undef LogSeverity // SetupAPI.h #defines this as DWORD
#include "nsString.h"
#include "nsIMutableArray.h"
#include "nsIJumpListBuilder.h"
#include "nsIJumpListItem.h"
#include "JumpListItem.h"
#include "nsIObserver.h"
#include "mozilla/Attributes.h"
namespace mozilla {
namespace widget {
class JumpListBuilder : public nsIJumpListBuilder,
public nsIObserver
{
virtual ~JumpListBuilder();
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIJUMPLISTBUILDER
NS_DECL_NSIOBSERVER
JumpListBuilder();
protected:
static bool sBuildingList;
private:
RefPtr<ICustomDestinationList> mJumpListMgr;
uint32_t mMaxItems;
bool mHasCommit;
nsCOMPtr<nsIThread> mIOThread;
bool IsSeparator(nsCOMPtr<nsIJumpListItem>& item);
nsresult TransferIObjectArrayToIMutableArray(IObjectArray *objArray, nsIMutableArray *removedItems);
nsresult RemoveIconCacheForItems(nsIMutableArray *removedItems);
nsresult RemoveIconCacheForAllItems();
friend class WinTaskbar;
};
} // namespace widget
} // namespace mozilla
#endif /* __JumpListBuilder_h__ */

View file

@ -0,0 +1,630 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "JumpListItem.h"
#include <shellapi.h>
#include <propvarutil.h>
#include <propkey.h>
#include "nsIFile.h"
#include "nsNetUtil.h"
#include "nsCRT.h"
#include "nsNetCID.h"
#include "nsCExternalHandlerService.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/Preferences.h"
#include "JumpListBuilder.h"
#include "WinUtils.h"
namespace mozilla {
namespace widget {
// ISUPPORTS Impl's
NS_IMPL_ISUPPORTS(JumpListItem,
nsIJumpListItem)
NS_IMPL_ISUPPORTS_INHERITED(JumpListSeparator,
JumpListItem,
nsIJumpListSeparator)
NS_IMPL_ISUPPORTS_INHERITED(JumpListLink,
JumpListItem,
nsIJumpListLink)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JumpListShortcut)
NS_INTERFACE_MAP_ENTRY(nsIJumpListShortcut)
NS_INTERFACE_MAP_END_INHERITING(JumpListItem)
NS_IMPL_CYCLE_COLLECTION(JumpListShortcut, mHandlerApp)
NS_IMPL_CYCLE_COLLECTING_ADDREF(JumpListShortcut)
NS_IMPL_CYCLE_COLLECTING_RELEASE(JumpListShortcut)
NS_IMETHODIMP JumpListItem::GetType(int16_t *aType)
{
NS_ENSURE_ARG_POINTER(aType);
*aType = mItemType;
return NS_OK;
}
NS_IMETHODIMP JumpListItem::Equals(nsIJumpListItem *aItem, bool *aResult)
{
NS_ENSURE_ARG_POINTER(aItem);
*aResult = false;
int16_t theType = nsIJumpListItem::JUMPLIST_ITEM_EMPTY;
if (NS_FAILED(aItem->GetType(&theType)))
return NS_OK;
// Make sure the types match.
if (Type() != theType)
return NS_OK;
*aResult = true;
return NS_OK;
}
/* link impl. */
NS_IMETHODIMP JumpListLink::GetUri(nsIURI **aURI)
{
NS_IF_ADDREF(*aURI = mURI);
return NS_OK;
}
NS_IMETHODIMP JumpListLink::SetUri(nsIURI *aURI)
{
mURI = aURI;
return NS_OK;
}
NS_IMETHODIMP JumpListLink::SetUriTitle(const nsAString &aUriTitle)
{
mUriTitle.Assign(aUriTitle);
return NS_OK;
}
NS_IMETHODIMP JumpListLink::GetUriTitle(nsAString& aUriTitle)
{
aUriTitle.Assign(mUriTitle);
return NS_OK;
}
NS_IMETHODIMP JumpListLink::GetUriHash(nsACString& aUriHash)
{
if (!mURI)
return NS_ERROR_NOT_AVAILABLE;
return mozilla::widget::FaviconHelper::HashURI(mCryptoHash, mURI, aUriHash);
}
NS_IMETHODIMP JumpListLink::CompareHash(nsIURI *aUri, bool *aResult)
{
nsresult rv;
if (!mURI) {
*aResult = !aUri;
return NS_OK;
}
NS_ENSURE_ARG_POINTER(aUri);
nsAutoCString hash1, hash2;
rv = mozilla::widget::FaviconHelper::HashURI(mCryptoHash, mURI, hash1);
NS_ENSURE_SUCCESS(rv, rv);
rv = mozilla::widget::FaviconHelper::HashURI(mCryptoHash, aUri, hash2);
NS_ENSURE_SUCCESS(rv, rv);
*aResult = hash1.Equals(hash2);
return NS_OK;
}
NS_IMETHODIMP JumpListLink::Equals(nsIJumpListItem *aItem, bool *aResult)
{
NS_ENSURE_ARG_POINTER(aItem);
nsresult rv;
*aResult = false;
int16_t theType = nsIJumpListItem::JUMPLIST_ITEM_EMPTY;
if (NS_FAILED(aItem->GetType(&theType)))
return NS_OK;
// Make sure the types match.
if (Type() != theType)
return NS_OK;
nsCOMPtr<nsIJumpListLink> link = do_QueryInterface(aItem, &rv);
if (NS_FAILED(rv))
return rv;
// Check the titles
nsAutoString title;
link->GetUriTitle(title);
if (!mUriTitle.Equals(title))
return NS_OK;
// Call the internal object's equals() method to check.
nsCOMPtr<nsIURI> theUri;
bool equals = false;
if (NS_SUCCEEDED(link->GetUri(getter_AddRefs(theUri)))) {
if (!theUri) {
if (!mURI)
*aResult = true;
return NS_OK;
}
if (NS_SUCCEEDED(theUri->Equals(mURI, &equals)) && equals) {
*aResult = true;
}
}
return NS_OK;
}
/* shortcut impl. */
NS_IMETHODIMP JumpListShortcut::GetApp(nsILocalHandlerApp **aApp)
{
NS_IF_ADDREF(*aApp = mHandlerApp);
return NS_OK;
}
NS_IMETHODIMP JumpListShortcut::SetApp(nsILocalHandlerApp *aApp)
{
mHandlerApp = aApp;
// Confirm the app is present on the system
if (!ExecutableExists(mHandlerApp))
return NS_ERROR_FILE_NOT_FOUND;
return NS_OK;
}
NS_IMETHODIMP JumpListShortcut::GetIconIndex(int32_t *aIconIndex)
{
NS_ENSURE_ARG_POINTER(aIconIndex);
*aIconIndex = mIconIndex;
return NS_OK;
}
NS_IMETHODIMP JumpListShortcut::SetIconIndex(int32_t aIconIndex)
{
mIconIndex = aIconIndex;
return NS_OK;
}
NS_IMETHODIMP JumpListShortcut::GetFaviconPageUri(nsIURI **aFaviconPageURI)
{
NS_IF_ADDREF(*aFaviconPageURI = mFaviconPageURI);
return NS_OK;
}
NS_IMETHODIMP JumpListShortcut::SetFaviconPageUri(nsIURI *aFaviconPageURI)
{
mFaviconPageURI = aFaviconPageURI;
return NS_OK;
}
NS_IMETHODIMP JumpListShortcut::Equals(nsIJumpListItem *aItem, bool *aResult)
{
NS_ENSURE_ARG_POINTER(aItem);
nsresult rv;
*aResult = false;
int16_t theType = nsIJumpListItem::JUMPLIST_ITEM_EMPTY;
if (NS_FAILED(aItem->GetType(&theType)))
return NS_OK;
// Make sure the types match.
if (Type() != theType)
return NS_OK;
nsCOMPtr<nsIJumpListShortcut> shortcut = do_QueryInterface(aItem, &rv);
if (NS_FAILED(rv))
return rv;
// Check the icon index
//int32_t idx;
//shortcut->GetIconIndex(&idx);
//if (mIconIndex != idx)
// return NS_OK;
// No need to check the icon page URI either
// Call the internal object's equals() method to check.
nsCOMPtr<nsILocalHandlerApp> theApp;
bool equals = false;
if (NS_SUCCEEDED(shortcut->GetApp(getter_AddRefs(theApp)))) {
if (!theApp) {
if (!mHandlerApp)
*aResult = true;
return NS_OK;
}
if (NS_SUCCEEDED(theApp->Equals(mHandlerApp, &equals)) && equals) {
*aResult = true;
}
}
return NS_OK;
}
/* internal helpers */
// (static) Creates a ShellLink that encapsulate a separator.
nsresult JumpListSeparator::GetSeparator(RefPtr<IShellLinkW>& aShellLink)
{
HRESULT hr;
IShellLinkW* psl;
// Create a IShellLink.
hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
IID_IShellLinkW, (LPVOID*)&psl);
if (FAILED(hr))
return NS_ERROR_UNEXPECTED;
IPropertyStore* pPropStore = nullptr;
hr = psl->QueryInterface(IID_IPropertyStore, (LPVOID*)&pPropStore);
if (FAILED(hr))
return NS_ERROR_UNEXPECTED;
PROPVARIANT pv;
InitPropVariantFromBoolean(TRUE, &pv);
pPropStore->SetValue(PKEY_AppUserModel_IsDestListSeparator, pv);
pPropStore->Commit();
pPropStore->Release();
PropVariantClear(&pv);
aShellLink = dont_AddRef(psl);
return NS_OK;
}
// (static) Creates a ShellLink that encapsulate a shortcut to local apps.
nsresult JumpListShortcut::GetShellLink(nsCOMPtr<nsIJumpListItem>& item,
RefPtr<IShellLinkW>& aShellLink,
nsCOMPtr<nsIThread> &aIOThread)
{
HRESULT hr;
IShellLinkW* psl;
nsresult rv;
// Shell links:
// http://msdn.microsoft.com/en-us/library/bb776891(VS.85).aspx
// http://msdn.microsoft.com/en-us/library/bb774950(VS.85).aspx
int16_t type;
if (NS_FAILED(item->GetType(&type)))
return NS_ERROR_INVALID_ARG;
if (type != nsIJumpListItem::JUMPLIST_ITEM_SHORTCUT)
return NS_ERROR_INVALID_ARG;
nsCOMPtr<nsIJumpListShortcut> shortcut = do_QueryInterface(item, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsILocalHandlerApp> handlerApp;
rv = shortcut->GetApp(getter_AddRefs(handlerApp));
NS_ENSURE_SUCCESS(rv, rv);
// Create a IShellLink
hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
IID_IShellLinkW, (LPVOID*)&psl);
if (FAILED(hr))
return NS_ERROR_UNEXPECTED;
// Retrieve the app path, title, description and optional command line args.
nsAutoString appPath, appTitle, appDescription, appArgs;
int32_t appIconIndex = 0;
// Path
nsCOMPtr<nsIFile> executable;
handlerApp->GetExecutable(getter_AddRefs(executable));
rv = executable->GetPath(appPath);
NS_ENSURE_SUCCESS(rv, rv);
// Command line parameters
uint32_t count = 0;
handlerApp->GetParameterCount(&count);
for (uint32_t idx = 0; idx < count; idx++) {
if (idx > 0)
appArgs.Append(' ');
nsAutoString param;
rv = handlerApp->GetParameter(idx, param);
if (NS_FAILED(rv))
return rv;
appArgs.Append(param);
}
handlerApp->GetName(appTitle);
handlerApp->GetDetailedDescription(appDescription);
bool useUriIcon = false; // if we want to use the URI icon
bool usedUriIcon = false; // if we did use the URI icon
shortcut->GetIconIndex(&appIconIndex);
nsCOMPtr<nsIURI> iconUri;
rv = shortcut->GetFaviconPageUri(getter_AddRefs(iconUri));
if (NS_SUCCEEDED(rv) && iconUri) {
useUriIcon = true;
}
// Store the title of the app
if (appTitle.Length() > 0) {
IPropertyStore* pPropStore = nullptr;
hr = psl->QueryInterface(IID_IPropertyStore, (LPVOID*)&pPropStore);
if (FAILED(hr))
return NS_ERROR_UNEXPECTED;
PROPVARIANT pv;
InitPropVariantFromString(appTitle.get(), &pv);
pPropStore->SetValue(PKEY_Title, pv);
pPropStore->Commit();
pPropStore->Release();
PropVariantClear(&pv);
}
// Store the rest of the params
psl->SetPath(appPath.get());
psl->SetDescription(appDescription.get());
psl->SetArguments(appArgs.get());
if (useUriIcon) {
nsString icoFilePath;
rv = mozilla::widget::FaviconHelper::ObtainCachedIconFile(iconUri,
icoFilePath,
aIOThread,
false);
if (NS_SUCCEEDED(rv)) {
// Always use the first icon in the ICO file
// our encoded icon only has 1 resource
psl->SetIconLocation(icoFilePath.get(), 0);
usedUriIcon = true;
}
}
// We didn't use an ICO via URI so fall back to the app icon
if (!usedUriIcon) {
psl->SetIconLocation(appPath.get(), appIconIndex);
}
aShellLink = dont_AddRef(psl);
return NS_OK;
}
// If successful fills in the aSame parameter
// aSame will be true if the path is in our icon cache
static nsresult IsPathInOurIconCache(nsCOMPtr<nsIJumpListShortcut>& aShortcut,
wchar_t *aPath, bool *aSame)
{
NS_ENSURE_ARG_POINTER(aPath);
NS_ENSURE_ARG_POINTER(aSame);
*aSame = false;
// Construct the path of our jump list cache
nsCOMPtr<nsIFile> jumpListCache;
nsresult rv = NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(jumpListCache));
NS_ENSURE_SUCCESS(rv, rv);
rv = jumpListCache->AppendNative(nsDependentCString(FaviconHelper::kJumpListCacheDir));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString jumpListCachePath;
rv = jumpListCache->GetPath(jumpListCachePath);
NS_ENSURE_SUCCESS(rv, rv);
// Construct the parent path of the passed in path
nsCOMPtr<nsIFile> passedInFile = do_CreateInstance("@mozilla.org/file/local;1");
NS_ENSURE_TRUE(passedInFile, NS_ERROR_FAILURE);
nsAutoString passedInPath(aPath);
rv = passedInFile->InitWithPath(passedInPath);
nsCOMPtr<nsIFile> passedInParentFile;
passedInFile->GetParent(getter_AddRefs(passedInParentFile));
nsAutoString passedInParentPath;
rv = jumpListCache->GetPath(passedInParentPath);
NS_ENSURE_SUCCESS(rv, rv);
*aSame = jumpListCachePath.Equals(passedInParentPath);
return NS_OK;
}
// (static) For a given IShellLink, create and return a populated nsIJumpListShortcut.
nsresult JumpListShortcut::GetJumpListShortcut(IShellLinkW *pLink, nsCOMPtr<nsIJumpListShortcut>& aShortcut)
{
NS_ENSURE_ARG_POINTER(pLink);
nsresult rv;
HRESULT hres;
nsCOMPtr<nsILocalHandlerApp> handlerApp =
do_CreateInstance(NS_LOCALHANDLERAPP_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
wchar_t buf[MAX_PATH];
// Path
hres = pLink->GetPath(buf, MAX_PATH, nullptr, SLGP_UNCPRIORITY);
if (FAILED(hres))
return NS_ERROR_INVALID_ARG;
nsCOMPtr<nsIFile> file;
nsDependentString filepath(buf);
rv = NS_NewLocalFile(filepath, false, getter_AddRefs(file));
NS_ENSURE_SUCCESS(rv, rv);
rv = handlerApp->SetExecutable(file);
NS_ENSURE_SUCCESS(rv, rv);
// Parameters
hres = pLink->GetArguments(buf, MAX_PATH);
if (SUCCEEDED(hres)) {
LPWSTR *arglist;
int32_t numArgs;
int32_t idx;
arglist = ::CommandLineToArgvW(buf, &numArgs);
if(arglist) {
for (idx = 0; idx < numArgs; idx++) {
// szArglist[i] is null terminated
nsDependentString arg(arglist[idx]);
handlerApp->AppendParameter(arg);
}
::LocalFree(arglist);
}
}
rv = aShortcut->SetApp(handlerApp);
NS_ENSURE_SUCCESS(rv, rv);
// Icon index or file location
int iconIdx = 0;
hres = pLink->GetIconLocation(buf, MAX_PATH, &iconIdx);
if (SUCCEEDED(hres)) {
// XXX How do we handle converting local files to images here? Do we need to?
aShortcut->SetIconIndex(iconIdx);
// Obtain the local profile directory and construct the output icon file path
// We only set the Icon Uri if we're sure it was from our icon cache.
bool isInOurCache;
if (NS_SUCCEEDED(IsPathInOurIconCache(aShortcut, buf, &isInOurCache)) &&
isInOurCache) {
nsCOMPtr<nsIURI> iconUri;
nsAutoString path(buf);
rv = NS_NewURI(getter_AddRefs(iconUri), path);
if (NS_SUCCEEDED(rv)) {
aShortcut->SetFaviconPageUri(iconUri);
}
}
}
// Do we need the title and description? Probably not since handler app doesn't compare
// these in equals.
return NS_OK;
}
// (static) ShellItems are used to encapsulate links to things. We currently only support URI links,
// but more support could be added, such as local file and directory links.
nsresult JumpListLink::GetShellItem(nsCOMPtr<nsIJumpListItem>& item, RefPtr<IShellItem2>& aShellItem)
{
IShellItem2 *psi = nullptr;
nsresult rv;
int16_t type;
if (NS_FAILED(item->GetType(&type)))
return NS_ERROR_INVALID_ARG;
if (type != nsIJumpListItem::JUMPLIST_ITEM_LINK)
return NS_ERROR_INVALID_ARG;
nsCOMPtr<nsIJumpListLink> link = do_QueryInterface(item, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> uri;
rv = link->GetUri(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString spec;
rv = uri->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
// Create the IShellItem
if (FAILED(WinUtils::SHCreateItemFromParsingName(
NS_ConvertASCIItoUTF16(spec).get(),
nullptr, IID_PPV_ARGS(&psi)))) {
return NS_ERROR_INVALID_ARG;
}
// Set the title
nsAutoString linkTitle;
link->GetUriTitle(linkTitle);
IPropertyStore* pPropStore = nullptr;
HRESULT hres = psi->GetPropertyStore(GPS_DEFAULT, IID_IPropertyStore, (void**)&pPropStore);
if (FAILED(hres))
return NS_ERROR_UNEXPECTED;
PROPVARIANT pv;
InitPropVariantFromString(linkTitle.get(), &pv);
// May fail due to shell item access permissions.
pPropStore->SetValue(PKEY_ItemName, pv);
pPropStore->Commit();
pPropStore->Release();
PropVariantClear(&pv);
aShellItem = dont_AddRef(psi);
return NS_OK;
}
// (static) For a given IShellItem, create and return a populated nsIJumpListLink.
nsresult JumpListLink::GetJumpListLink(IShellItem *pItem, nsCOMPtr<nsIJumpListLink>& aLink)
{
NS_ENSURE_ARG_POINTER(pItem);
// We assume for now these are URI links, but through properties we could
// query and create other types.
nsresult rv;
LPWSTR lpstrName = nullptr;
if (SUCCEEDED(pItem->GetDisplayName(SIGDN_URL, &lpstrName))) {
nsCOMPtr<nsIURI> uri;
nsAutoString spec(lpstrName);
rv = NS_NewURI(getter_AddRefs(uri), NS_ConvertUTF16toUTF8(spec));
if (NS_FAILED(rv))
return NS_ERROR_INVALID_ARG;
aLink->SetUri(uri);
::CoTaskMemFree(lpstrName);
}
return NS_OK;
}
// Confirm the app is on the system
bool JumpListShortcut::ExecutableExists(nsCOMPtr<nsILocalHandlerApp>& handlerApp)
{
nsresult rv;
if (!handlerApp)
return false;
nsCOMPtr<nsIFile> executable;
rv = handlerApp->GetExecutable(getter_AddRefs(executable));
if (NS_SUCCEEDED(rv) && executable) {
bool exists;
executable->Exists(&exists);
return exists;
}
return false;
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,132 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __JumpListItem_h__
#define __JumpListItem_h__
#include <windows.h>
#include <shobjidl.h>
#undef LogSeverity // SetupAPI.h #defines this as DWORD
#include "mozilla/RefPtr.h"
#include "nsIJumpListItem.h" // defines nsIJumpListItem
#include "nsIMIMEInfo.h" // defines nsILocalHandlerApp
#include "nsTArray.h"
#include "nsIMutableArray.h"
#include "nsCOMPtr.h"
#include "nsIURI.h"
#include "nsICryptoHash.h"
#include "nsString.h"
#include "nsCycleCollectionParticipant.h"
class nsIThread;
namespace mozilla {
namespace widget {
class JumpListItem : public nsIJumpListItem
{
public:
JumpListItem() :
mItemType(nsIJumpListItem::JUMPLIST_ITEM_EMPTY)
{}
JumpListItem(int32_t type) :
mItemType(type)
{}
NS_DECL_ISUPPORTS
NS_DECL_NSIJUMPLISTITEM
static const char kJumpListCacheDir[];
protected:
virtual ~JumpListItem()
{}
short Type() { return mItemType; }
short mItemType;
};
class JumpListSeparator : public JumpListItem, public nsIJumpListSeparator
{
~JumpListSeparator() {}
public:
JumpListSeparator() :
JumpListItem(nsIJumpListItem::JUMPLIST_ITEM_SEPARATOR)
{}
NS_DECL_ISUPPORTS_INHERITED
NS_IMETHOD GetType(int16_t *aType) override { return JumpListItem::GetType(aType); }
NS_IMETHOD Equals(nsIJumpListItem *item, bool *_retval) override { return JumpListItem::Equals(item, _retval); }
static nsresult GetSeparator(RefPtr<IShellLinkW>& aShellLink);
};
class JumpListLink : public JumpListItem, public nsIJumpListLink
{
~JumpListLink() {}
public:
JumpListLink() :
JumpListItem(nsIJumpListItem::JUMPLIST_ITEM_LINK)
{}
NS_DECL_ISUPPORTS_INHERITED
NS_IMETHOD GetType(int16_t *aType) override { return JumpListItem::GetType(aType); }
NS_IMETHOD Equals(nsIJumpListItem *item, bool *_retval) override;
NS_DECL_NSIJUMPLISTLINK
static nsresult GetShellItem(nsCOMPtr<nsIJumpListItem>& item, RefPtr<IShellItem2>& aShellItem);
static nsresult GetJumpListLink(IShellItem *pItem, nsCOMPtr<nsIJumpListLink>& aLink);
protected:
nsString mUriTitle;
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsICryptoHash> mCryptoHash;
};
class JumpListShortcut : public JumpListItem, public nsIJumpListShortcut
{
~JumpListShortcut() {}
public:
JumpListShortcut() :
JumpListItem(nsIJumpListItem::JUMPLIST_ITEM_SHORTCUT)
{}
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(JumpListShortcut, JumpListItem)
NS_IMETHOD GetType(int16_t *aType) override { return JumpListItem::GetType(aType); }
NS_IMETHOD Equals(nsIJumpListItem *item, bool *_retval) override;
NS_DECL_NSIJUMPLISTSHORTCUT
static nsresult GetShellLink(nsCOMPtr<nsIJumpListItem>& item,
RefPtr<IShellLinkW>& aShellLink,
nsCOMPtr<nsIThread> &aIOThread);
static nsresult GetJumpListShortcut(IShellLinkW *pLink, nsCOMPtr<nsIJumpListShortcut>& aShortcut);
static nsresult GetOutputIconPath(nsCOMPtr<nsIURI> aFaviconPageURI,
nsCOMPtr<nsIFile> &aICOFile);
protected:
int32_t mIconIndex;
nsCOMPtr<nsIURI> mFaviconPageURI;
nsCOMPtr<nsILocalHandlerApp> mHandlerApp;
bool ExecutableExists(nsCOMPtr<nsILocalHandlerApp>& handlerApp);
static nsresult ObtainCachedIconFile(nsCOMPtr<nsIURI> aFaviconPageURI,
nsString &aICOFilePath,
nsCOMPtr<nsIThread> &aIOThread);
static nsresult CacheIconFileFromFaviconURIAsync(nsCOMPtr<nsIURI> aFaviconPageURI,
nsCOMPtr<nsIFile> aICOFile,
nsCOMPtr<nsIThread> &aIOThread);
};
} // namespace widget
} // namespace mozilla
#endif /* __JumpListItem_h__ */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,161 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* LSPs are evil little bits of code that are allowed to inject into our
* networking stack by Windows. Once they have wormed into our process
* they gnaw at our innards until we crash. Here we force the buggers
* into the light by recording them in our crash information.
* We do the enumeration on a thread because I'm concerned about startup perf
* on machines with several LSPs.
*/
#if _WIN32_WINNT < 0x0600
// Redefining _WIN32_WINNT for some Vista APIs that we call
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#endif
#include "nsICrashReporter.h"
#include "nsISupportsImpl.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
#include "nsQueryObject.h"
#include "nsWindowsHelpers.h"
#include <windows.h>
#include <rpc.h>
#include <ws2spi.h>
namespace mozilla {
namespace crashreporter {
class LSPAnnotationGatherer : public Runnable
{
~LSPAnnotationGatherer() {}
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIRUNNABLE
void Annotate();
nsCString mString;
nsCOMPtr<nsIThread> mThread;
};
NS_IMPL_ISUPPORTS(LSPAnnotationGatherer, nsIRunnable)
void
LSPAnnotationGatherer::Annotate()
{
nsCOMPtr<nsICrashReporter> cr =
do_GetService("@mozilla.org/toolkit/crash-reporter;1");
bool enabled;
if (cr && NS_SUCCEEDED(cr->GetEnabled(&enabled)) && enabled) {
cr->AnnotateCrashReport(NS_LITERAL_CSTRING("Winsock_LSP"), mString);
}
mThread->AsyncShutdown();
}
NS_IMETHODIMP
LSPAnnotationGatherer::Run()
{
PR_SetCurrentThreadName("LSP Annotator");
mThread = NS_GetCurrentThread();
DWORD size = 0;
int err;
// Get the size of the buffer we need
if (SOCKET_ERROR != WSCEnumProtocols(nullptr, nullptr, &size, &err) ||
err != WSAENOBUFS) {
// Er, what?
NS_NOTREACHED("WSCEnumProtocols suceeded when it should have failed ...");
return NS_ERROR_FAILURE;
}
auto byteArray = MakeUnique<char[]>(size);
WSAPROTOCOL_INFOW* providers =
reinterpret_cast<WSAPROTOCOL_INFOW*>(byteArray.get());
int n = WSCEnumProtocols(nullptr, providers, &size, &err);
if (n == SOCKET_ERROR) {
// Lame. We provided the right size buffer; we'll just give up now.
NS_WARNING("Could not get LSP list");
return NS_ERROR_FAILURE;
}
nsCString str;
for (int i = 0; i < n; i++) {
AppendUTF16toUTF8(nsDependentString(providers[i].szProtocol), str);
str.AppendLiteral(" : ");
str.AppendInt(providers[i].iVersion);
str.AppendLiteral(" : ");
str.AppendInt(providers[i].iAddressFamily);
str.AppendLiteral(" : ");
str.AppendInt(providers[i].iSocketType);
str.AppendLiteral(" : ");
str.AppendInt(providers[i].iProtocol);
str.AppendLiteral(" : ");
str.AppendPrintf("0x%x", providers[i].dwServiceFlags1);
str.AppendLiteral(" : ");
str.AppendPrintf("0x%x", providers[i].dwProviderFlags);
str.AppendLiteral(" : ");
wchar_t path[MAX_PATH];
int pathLen = MAX_PATH;
if (!WSCGetProviderPath(&providers[i].ProviderId, path, &pathLen, &err)) {
AppendUTF16toUTF8(nsDependentString(path), str);
}
str.AppendLiteral(" : ");
// If WSCGetProviderInfo is available, we should call it to obtain the
// category flags for this provider. When present, these flags inform
// Windows as to which order to chain the providers.
nsModuleHandle ws2_32(LoadLibraryW(L"ws2_32.dll"));
if (ws2_32) {
decltype(WSCGetProviderInfo)* pWSCGetProviderInfo =
reinterpret_cast<decltype(WSCGetProviderInfo)*>(
GetProcAddress(ws2_32, "WSCGetProviderInfo"));
if (pWSCGetProviderInfo) {
DWORD categoryInfo;
size_t categoryInfoSize = sizeof(categoryInfo);
if (!pWSCGetProviderInfo(&providers[i].ProviderId,
ProviderInfoLspCategories,
(PBYTE)&categoryInfo, &categoryInfoSize, 0,
&err)) {
str.AppendPrintf("0x%x", categoryInfo);
}
}
}
str.AppendLiteral(" : ");
if (providers[i].ProtocolChain.ChainLen <= BASE_PROTOCOL) {
// If we're dealing with a catalog entry that identifies an individual
// base or layer provider, log its provider GUID.
RPC_CSTR provIdStr = nullptr;
if (UuidToStringA(&providers[i].ProviderId, &provIdStr) == RPC_S_OK) {
str.Append(reinterpret_cast<char*>(provIdStr));
RpcStringFreeA(&provIdStr);
}
}
if (i + 1 != n) {
str.AppendLiteral(" \n ");
}
}
mString = str;
NS_DispatchToMainThread(NewRunnableMethod(this, &LSPAnnotationGatherer::Annotate));
return NS_OK;
}
void LSPAnnotate()
{
nsCOMPtr<nsIThread> thread;
nsCOMPtr<nsIRunnable> runnable =
do_QueryObject(new LSPAnnotationGatherer());
NS_NewThread(getter_AddRefs(thread), runnable);
}
} // namespace crashreporter
} // namespace mozilla

View file

@ -0,0 +1,31 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=99: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PCompositorBridge;
using mozilla::gfx::IntSize from "mozilla/gfx/Point.h";
namespace mozilla {
namespace widget {
sync protocol PCompositorWidget
{
manager PCompositorBridge;
parent:
sync EnterPresentLock();
sync LeavePresentLock();
async UpdateTransparency(int32_t aMode);
sync ClearTransparentWindow();
async __delete__();
child:
async ObserveVsync();
async UnobserveVsync();
};
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,23 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=99: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// This file is a stub, for platforms that do not yet support out-of-process
// compositing or do not need specialized types to do so.
using mozilla::WindowsHandle from "ipc/IPCMessageUtils.h";
namespace mozilla {
namespace widget {
struct CompositorWidgetInitData
{
WindowsHandle hWnd;
uintptr_t widgetKey;
int32_t transparencyMode;
};
} // namespace widget
} // namespace mozilla

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,431 @@
/* vim: se cin sw=2 ts=2 et : */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "TaskbarPreview.h"
#include <nsITaskbarPreviewController.h>
#include <windows.h>
#include <nsError.h>
#include <nsCOMPtr.h>
#include <nsIWidget.h>
#include <nsIBaseWindow.h>
#include <nsIObserverService.h>
#include <nsServiceManagerUtils.h>
#include "nsUXThemeData.h"
#include "nsWindow.h"
#include "nsAppShell.h"
#include "TaskbarPreviewButton.h"
#include "WinUtils.h"
#include "mozilla/dom/HTMLCanvasElement.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/DataSurfaceHelpers.h"
#include "mozilla/Telemetry.h"
// Defined in dwmapi in a header that needs a higher numbered _WINNT #define
#define DWM_SIT_DISPLAYFRAME 0x1
namespace mozilla {
namespace widget {
///////////////////////////////////////////////////////////////////////////////
// TaskbarPreview
TaskbarPreview::TaskbarPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell)
: mTaskbar(aTaskbar),
mController(aController),
mWnd(aHWND),
mVisible(false),
mDocShell(do_GetWeakReference(aShell))
{
// TaskbarPreview may outlive the WinTaskbar that created it
::CoInitialize(nullptr);
WindowHook &hook = GetWindowHook();
hook.AddMonitor(WM_DESTROY, MainWindowHook, this);
}
TaskbarPreview::~TaskbarPreview() {
// Avoid dangling pointer
if (sActivePreview == this)
sActivePreview = nullptr;
// Our subclass should have invoked DetachFromNSWindow already.
NS_ASSERTION(!mWnd, "TaskbarPreview::DetachFromNSWindow was not called before destruction");
// Make sure to release before potentially uninitializing COM
mTaskbar = nullptr;
::CoUninitialize();
}
NS_IMETHODIMP
TaskbarPreview::SetController(nsITaskbarPreviewController *aController) {
NS_ENSURE_ARG(aController);
mController = aController;
return NS_OK;
}
NS_IMETHODIMP
TaskbarPreview::GetController(nsITaskbarPreviewController **aController) {
NS_ADDREF(*aController = mController);
return NS_OK;
}
NS_IMETHODIMP
TaskbarPreview::GetTooltip(nsAString &aTooltip) {
aTooltip = mTooltip;
return NS_OK;
}
NS_IMETHODIMP
TaskbarPreview::SetTooltip(const nsAString &aTooltip) {
mTooltip = aTooltip;
return CanMakeTaskbarCalls() ? UpdateTooltip() : NS_OK;
}
NS_IMETHODIMP
TaskbarPreview::SetVisible(bool visible) {
if (mVisible == visible) return NS_OK;
mVisible = visible;
// If the nsWindow has already been destroyed but the caller is still trying
// to use it then just pretend that everything succeeded. The caller doesn't
// actually have a way to detect this since it's the same case as when we
// CanMakeTaskbarCalls returns false.
if (!mWnd)
return NS_OK;
return visible ? Enable() : Disable();
}
NS_IMETHODIMP
TaskbarPreview::GetVisible(bool *visible) {
*visible = mVisible;
return NS_OK;
}
NS_IMETHODIMP
TaskbarPreview::SetActive(bool active) {
if (active)
sActivePreview = this;
else if (sActivePreview == this)
sActivePreview = nullptr;
return CanMakeTaskbarCalls() ? ShowActive(active) : NS_OK;
}
NS_IMETHODIMP
TaskbarPreview::GetActive(bool *active) {
*active = sActivePreview == this;
return NS_OK;
}
NS_IMETHODIMP
TaskbarPreview::Invalidate() {
if (!mVisible)
return NS_OK;
// DWM Composition is required for previews
if (!nsUXThemeData::CheckForCompositor())
return NS_OK;
HWND previewWindow = PreviewWindow();
return FAILED(WinUtils::dwmInvalidateIconicBitmapsPtr(previewWindow))
? NS_ERROR_FAILURE
: NS_OK;
}
nsresult
TaskbarPreview::UpdateTaskbarProperties() {
nsresult rv = UpdateTooltip();
// If we are the active preview and our window is the active window, restore
// our active state - otherwise some other non-preview window is now active
// and should be displayed as so.
if (sActivePreview == this) {
if (mWnd == ::GetActiveWindow()) {
nsresult rvActive = ShowActive(true);
if (NS_FAILED(rvActive))
rv = rvActive;
} else {
sActivePreview = nullptr;
}
}
return rv;
}
nsresult
TaskbarPreview::Enable() {
nsresult rv = NS_OK;
if (CanMakeTaskbarCalls()) {
rv = UpdateTaskbarProperties();
} else {
WindowHook &hook = GetWindowHook();
hook.AddMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(), MainWindowHook, this);
}
return rv;
}
nsresult
TaskbarPreview::Disable() {
if (!IsWindowAvailable()) {
// Window is already destroyed
return NS_OK;
}
WindowHook &hook = GetWindowHook();
(void) hook.RemoveMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(), MainWindowHook, this);
return NS_OK;
}
bool
TaskbarPreview::IsWindowAvailable() const {
if (mWnd) {
nsWindow* win = WinUtils::GetNSWindowPtr(mWnd);
if(win && !win->Destroyed()) {
return true;
}
}
return false;
}
void
TaskbarPreview::DetachFromNSWindow() {
WindowHook &hook = GetWindowHook();
hook.RemoveMonitor(WM_DESTROY, MainWindowHook, this);
mWnd = nullptr;
}
LRESULT
TaskbarPreview::WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam) {
switch (nMsg) {
case WM_DWMSENDICONICTHUMBNAIL:
{
uint32_t width = HIWORD(lParam);
uint32_t height = LOWORD(lParam);
float aspectRatio = width/float(height);
nsresult rv;
float preferredAspectRatio;
rv = mController->GetThumbnailAspectRatio(&preferredAspectRatio);
if (NS_FAILED(rv))
break;
uint32_t thumbnailWidth = width;
uint32_t thumbnailHeight = height;
if (aspectRatio > preferredAspectRatio) {
thumbnailWidth = uint32_t(thumbnailHeight * preferredAspectRatio);
} else {
thumbnailHeight = uint32_t(thumbnailWidth / preferredAspectRatio);
}
DrawBitmap(thumbnailWidth, thumbnailHeight, false);
}
break;
case WM_DWMSENDICONICLIVEPREVIEWBITMAP:
{
uint32_t width, height;
nsresult rv;
rv = mController->GetWidth(&width);
if (NS_FAILED(rv))
break;
rv = mController->GetHeight(&height);
if (NS_FAILED(rv))
break;
double scale = nsIWidget::DefaultScaleOverride();
if (scale <= 0.0) {
scale = WinUtils::LogToPhysFactor(PreviewWindow());
}
DrawBitmap(NSToIntRound(scale * width), NSToIntRound(scale * height), true);
}
break;
}
return ::DefWindowProcW(PreviewWindow(), nMsg, wParam, lParam);
}
bool
TaskbarPreview::CanMakeTaskbarCalls() {
// If the nsWindow has already been destroyed and we know it but our caller
// clearly doesn't so we can't make any calls.
if (!mWnd)
return false;
// Certain functions like SetTabOrder seem to require a visible window. During
// window close, the window seems to be hidden before being destroyed.
if (!::IsWindowVisible(mWnd))
return false;
if (mVisible) {
nsWindow *window = WinUtils::GetNSWindowPtr(mWnd);
NS_ASSERTION(window, "Could not get nsWindow from HWND");
return window->HasTaskbarIconBeenCreated();
}
return false;
}
WindowHook&
TaskbarPreview::GetWindowHook() {
nsWindow *window = WinUtils::GetNSWindowPtr(mWnd);
NS_ASSERTION(window, "Cannot use taskbar previews in an embedded context!");
return window->GetWindowHook();
}
void
TaskbarPreview::EnableCustomDrawing(HWND aHWND, bool aEnable) {
BOOL enabled = aEnable;
WinUtils::dwmSetWindowAttributePtr(
aHWND,
DWMWA_FORCE_ICONIC_REPRESENTATION,
&enabled,
sizeof(enabled));
WinUtils::dwmSetWindowAttributePtr(
aHWND,
DWMWA_HAS_ICONIC_BITMAP,
&enabled,
sizeof(enabled));
}
nsresult
TaskbarPreview::UpdateTooltip() {
NS_ASSERTION(CanMakeTaskbarCalls() && mVisible, "UpdateTooltip called on invisible tab preview");
if (FAILED(mTaskbar->SetThumbnailTooltip(PreviewWindow(), mTooltip.get())))
return NS_ERROR_FAILURE;
return NS_OK;
}
void
TaskbarPreview::DrawBitmap(uint32_t width, uint32_t height, bool isPreview) {
nsresult rv;
nsCOMPtr<nsITaskbarPreviewCallback> callback =
do_CreateInstance("@mozilla.org/widget/taskbar-preview-callback;1", &rv);
if (NS_FAILED(rv)) {
return;
}
((TaskbarPreviewCallback*)callback.get())->SetPreview(this);
if (isPreview) {
((TaskbarPreviewCallback*)callback.get())->SetIsPreview();
mController->RequestPreview(callback);
} else {
mController->RequestThumbnail(callback, width, height);
}
}
///////////////////////////////////////////////////////////////////////////////
// TaskbarPreviewCallback
NS_IMPL_ISUPPORTS(TaskbarPreviewCallback, nsITaskbarPreviewCallback)
/* void done (in nsISupports aCanvas, in boolean aDrawBorder); */
NS_IMETHODIMP
TaskbarPreviewCallback::Done(nsISupports *aCanvas, bool aDrawBorder) {
// We create and destroy TaskbarTabPreviews from front end code in response
// to TabOpen and TabClose events. Each TaskbarTabPreview creates and owns a
// proxy HWND which it hands to Windows as a tab identifier. When a tab
// closes, TaskbarTabPreview Disable() method is called by front end, which
// destroys the proxy window and clears mProxyWindow which is the HWND
// returned from PreviewWindow(). So, since this is async, we should check to
// be sure the tab is still alive before doing all this gfx work and making
// dwm calls. To accomplish this we check the result of PreviewWindow().
if (!aCanvas || !mPreview || !mPreview->PreviewWindow() ||
!mPreview->IsWindowAvailable()) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMHTMLCanvasElement> domcanvas(do_QueryInterface(aCanvas));
dom::HTMLCanvasElement * canvas = ((dom::HTMLCanvasElement*)domcanvas.get());
if (!canvas) {
return NS_ERROR_FAILURE;
}
RefPtr<gfx::SourceSurface> source = canvas->GetSurfaceSnapshot();
if (!source) {
return NS_ERROR_FAILURE;
}
RefPtr<gfxWindowsSurface> target = new gfxWindowsSurface(source->GetSize(),
gfx::SurfaceFormat::A8R8G8B8_UINT32);
if (!target) {
return NS_ERROR_FAILURE;
}
RefPtr<gfx::DataSourceSurface> srcSurface = source->GetDataSurface();
RefPtr<gfxImageSurface> imageSurface = target->GetAsImageSurface();
if (!srcSurface || !imageSurface) {
return NS_ERROR_FAILURE;
}
gfx::DataSourceSurface::MappedSurface sourceMap;
srcSurface->Map(gfx::DataSourceSurface::READ, &sourceMap);
mozilla::gfx::CopySurfaceDataToPackedArray(sourceMap.mData,
imageSurface->Data(),
srcSurface->GetSize(),
sourceMap.mStride,
BytesPerPixel(srcSurface->GetFormat()));
srcSurface->Unmap();
HDC hDC = target->GetDC();
HBITMAP hBitmap = (HBITMAP)GetCurrentObject(hDC, OBJ_BITMAP);
DWORD flags = aDrawBorder ? DWM_SIT_DISPLAYFRAME : 0;
POINT pptClient = { 0, 0 };
HRESULT hr;
if (!mIsThumbnail) {
hr = WinUtils::dwmSetIconicLivePreviewBitmapPtr(mPreview->PreviewWindow(),
hBitmap, &pptClient, flags);
} else {
hr = WinUtils::dwmSetIconicThumbnailPtr(mPreview->PreviewWindow(),
hBitmap, flags);
}
MOZ_ASSERT(SUCCEEDED(hr));
return NS_OK;
}
/* static */
bool
TaskbarPreview::MainWindowHook(void *aContext,
HWND hWnd, UINT nMsg,
WPARAM wParam, LPARAM lParam,
LRESULT *aResult)
{
NS_ASSERTION(nMsg == nsAppShell::GetTaskbarButtonCreatedMessage() ||
nMsg == WM_DESTROY,
"Window hook proc called with wrong message");
NS_ASSERTION(aContext, "Null context in MainWindowHook");
if (!aContext)
return false;
TaskbarPreview *preview = reinterpret_cast<TaskbarPreview*>(aContext);
if (nMsg == WM_DESTROY) {
// nsWindow is being destroyed
// We can't really do anything at this point including removing hooks
return false;
} else {
nsWindow *window = WinUtils::GetNSWindowPtr(preview->mWnd);
if (window) {
window->SetHasTaskbarIconBeenCreated();
if (preview->mVisible)
preview->UpdateTaskbarProperties();
}
}
return false;
}
TaskbarPreview *
TaskbarPreview::sActivePreview = nullptr;
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,140 @@
/* vim: se cin sw=2 ts=2 et : */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __mozilla_widget_TaskbarPreview_h__
#define __mozilla_widget_TaskbarPreview_h__
#include <windows.h>
#include <shobjidl.h>
#undef LogSeverity // SetupAPI.h #defines this as DWORD
#include "mozilla/RefPtr.h"
#include <nsITaskbarPreview.h>
#include <nsITaskbarPreviewController.h>
#include <nsString.h>
#include <nsWeakPtr.h>
#include <nsIDocShell.h>
#include "WindowHook.h"
namespace mozilla {
namespace widget {
class TaskbarPreviewCallback;
class TaskbarPreview : public nsITaskbarPreview
{
public:
TaskbarPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell);
friend class TaskbarPreviewCallback;
NS_DECL_NSITASKBARPREVIEW
protected:
virtual ~TaskbarPreview();
// Called to update ITaskbarList4 dependent properties
virtual nsresult UpdateTaskbarProperties();
// Invoked when the preview is made visible
virtual nsresult Enable();
// Invoked when the preview is made invisible
virtual nsresult Disable();
// Detaches this preview from the nsWindow instance it's tied to
virtual void DetachFromNSWindow();
// Determines if the window is available and a destroy has not yet started
bool IsWindowAvailable() const;
// Marks this preview as being active
virtual nsresult ShowActive(bool active) = 0;
// Gets a reference to the window used to handle the preview messages
virtual HWND& PreviewWindow() = 0;
// Window procedure for the PreviewWindow (hooked for window previews)
virtual LRESULT WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam);
// Returns whether or not the taskbar icon has been created for mWnd The
// ITaskbarList4 API requires that we wait until the icon has been created
// before we can call its methods.
bool CanMakeTaskbarCalls();
// Gets the WindowHook for the nsWindow
WindowHook &GetWindowHook();
// Enables/disables custom drawing for the given window
static void EnableCustomDrawing(HWND aHWND, bool aEnable);
// MSCOM Taskbar interface
RefPtr<ITaskbarList4> mTaskbar;
// Controller for this preview
nsCOMPtr<nsITaskbarPreviewController> mController;
// The HWND to the nsWindow that this object previews
HWND mWnd;
// Whether or not this preview is visible
bool mVisible;
private:
// Called when the tooltip should be updated
nsresult UpdateTooltip();
// Requests the controller to draw into a canvas of the given width and
// height. The resulting bitmap is sent to the DWM to display.
void DrawBitmap(uint32_t width, uint32_t height, bool isPreview);
// WindowHook procedure for hooking mWnd
static bool MainWindowHook(void *aContext,
HWND hWnd, UINT nMsg,
WPARAM wParam, LPARAM lParam,
LRESULT *aResult);
// Docshell corresponding to the <window> the nsWindow contains
nsWeakPtr mDocShell;
nsString mTooltip;
// The preview currently marked as active in the taskbar. nullptr if no
// preview is active (some other window is).
static TaskbarPreview *sActivePreview;
};
/*
* Callback object TaskbarPreview hands to preview controllers when we
* request async thumbnail or live preview images. Controllers invoke
* this interface once they have aquired the requested image.
*/
class TaskbarPreviewCallback : public nsITaskbarPreviewCallback
{
public:
TaskbarPreviewCallback() :
mIsThumbnail(true) {
}
NS_DECL_ISUPPORTS
NS_DECL_NSITASKBARPREVIEWCALLBACK
void SetPreview(TaskbarPreview* aPreview) {
mPreview = aPreview;
}
void SetIsPreview() {
mIsThumbnail = false;
}
protected:
virtual ~TaskbarPreviewCallback() {}
private:
RefPtr<TaskbarPreview> mPreview;
bool mIsThumbnail;
};
} // namespace widget
} // namespace mozilla
#endif /* __mozilla_widget_TaskbarPreview_h__ */

View file

@ -0,0 +1,145 @@
/* vim: se cin sw=2 ts=2 et : */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <windows.h>
#include <strsafe.h>
#include "TaskbarWindowPreview.h"
#include "TaskbarPreviewButton.h"
#include "nsWindowGfx.h"
#include <imgIContainer.h>
namespace mozilla {
namespace widget {
NS_IMPL_ISUPPORTS(TaskbarPreviewButton, nsITaskbarPreviewButton, nsISupportsWeakReference)
TaskbarPreviewButton::TaskbarPreviewButton(TaskbarWindowPreview* preview, uint32_t index)
: mPreview(preview), mIndex(index)
{
}
TaskbarPreviewButton::~TaskbarPreviewButton() {
SetVisible(false);
}
NS_IMETHODIMP
TaskbarPreviewButton::GetTooltip(nsAString &aTooltip) {
aTooltip = mTooltip;
return NS_OK;
}
NS_IMETHODIMP
TaskbarPreviewButton::SetTooltip(const nsAString &aTooltip) {
mTooltip = aTooltip;
size_t destLength = sizeof Button().szTip / (sizeof Button().szTip[0]);
wchar_t *tooltip = &(Button().szTip[0]);
StringCchCopyNW(tooltip,
destLength,
mTooltip.get(),
mTooltip.Length());
return Update();
}
NS_IMETHODIMP
TaskbarPreviewButton::GetDismissOnClick(bool *dismiss) {
*dismiss = (Button().dwFlags & THBF_DISMISSONCLICK) == THBF_DISMISSONCLICK;
return NS_OK;
}
NS_IMETHODIMP
TaskbarPreviewButton::SetDismissOnClick(bool dismiss) {
if (dismiss)
Button().dwFlags |= THBF_DISMISSONCLICK;
else
Button().dwFlags &= ~THBF_DISMISSONCLICK;
return Update();
}
NS_IMETHODIMP
TaskbarPreviewButton::GetHasBorder(bool *hasBorder) {
*hasBorder = (Button().dwFlags & THBF_NOBACKGROUND) != THBF_NOBACKGROUND;
return NS_OK;
}
NS_IMETHODIMP
TaskbarPreviewButton::SetHasBorder(bool hasBorder) {
if (hasBorder)
Button().dwFlags &= ~THBF_NOBACKGROUND;
else
Button().dwFlags |= THBF_NOBACKGROUND;
return Update();
}
NS_IMETHODIMP
TaskbarPreviewButton::GetDisabled(bool *disabled) {
*disabled = (Button().dwFlags & THBF_DISABLED) == THBF_DISABLED;
return NS_OK;
}
NS_IMETHODIMP
TaskbarPreviewButton::SetDisabled(bool disabled) {
if (disabled)
Button().dwFlags |= THBF_DISABLED;
else
Button().dwFlags &= ~THBF_DISABLED;
return Update();
}
NS_IMETHODIMP
TaskbarPreviewButton::GetImage(imgIContainer **img) {
if (mImage)
NS_ADDREF(*img = mImage);
else
*img = nullptr;
return NS_OK;
}
NS_IMETHODIMP
TaskbarPreviewButton::SetImage(imgIContainer *img) {
if (Button().hIcon)
::DestroyIcon(Button().hIcon);
if (img) {
nsresult rv;
rv = nsWindowGfx::CreateIcon(img, false, 0, 0,
nsWindowGfx::GetIconMetrics(nsWindowGfx::kRegularIcon),
&Button().hIcon);
NS_ENSURE_SUCCESS(rv, rv);
} else {
Button().hIcon = nullptr;
}
return Update();
}
NS_IMETHODIMP
TaskbarPreviewButton::GetVisible(bool *visible) {
*visible = (Button().dwFlags & THBF_HIDDEN) != THBF_HIDDEN;
return NS_OK;
}
NS_IMETHODIMP
TaskbarPreviewButton::SetVisible(bool visible) {
if (visible)
Button().dwFlags &= ~THBF_HIDDEN;
else
Button().dwFlags |= THBF_HIDDEN;
return Update();
}
THUMBBUTTON&
TaskbarPreviewButton::Button() {
return mPreview->mThumbButtons[mIndex];
}
nsresult
TaskbarPreviewButton::Update() {
return mPreview->UpdateButton(mIndex);
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,48 @@
/* vim: se cin sw=2 ts=2 et : */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __mozilla_widget_TaskbarPreviewButton_h__
#define __mozilla_widget_TaskbarPreviewButton_h__
#include <windows.h>
#include <shobjidl.h>
#undef LogSeverity // SetupAPI.h #defines this as DWORD
#include "mozilla/RefPtr.h"
#include <nsITaskbarPreviewButton.h>
#include <nsString.h>
#include <nsWeakReference.h>
namespace mozilla {
namespace widget {
class TaskbarWindowPreview;
class TaskbarPreviewButton : public nsITaskbarPreviewButton, public nsSupportsWeakReference
{
virtual ~TaskbarPreviewButton();
public:
TaskbarPreviewButton(TaskbarWindowPreview* preview, uint32_t index);
NS_DECL_ISUPPORTS
NS_DECL_NSITASKBARPREVIEWBUTTON
private:
THUMBBUTTON& Button();
nsresult Update();
RefPtr<TaskbarWindowPreview> mPreview;
uint32_t mIndex;
nsString mTooltip;
nsCOMPtr<imgIContainer> mImage;
};
} // namespace widget
} // namespace mozilla
#endif /* __mozilla_widget_TaskbarPreviewButton_h__ */

View file

@ -0,0 +1,357 @@
/* vim: se cin sw=2 ts=2 et : */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "TaskbarTabPreview.h"
#include "nsWindowGfx.h"
#include "nsUXThemeData.h"
#include "WinUtils.h"
#include <nsITaskbarPreviewController.h>
#define TASKBARPREVIEW_HWNDID L"TaskbarTabPreviewHwnd"
namespace mozilla {
namespace widget {
NS_IMPL_ISUPPORTS(TaskbarTabPreview, nsITaskbarTabPreview)
const wchar_t *const kWindowClass = L"MozillaTaskbarPreviewClass";
TaskbarTabPreview::TaskbarTabPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell)
: TaskbarPreview(aTaskbar, aController, aHWND, aShell),
mProxyWindow(nullptr),
mIcon(nullptr),
mRegistered(false)
{
WindowHook &hook = GetWindowHook();
hook.AddMonitor(WM_WINDOWPOSCHANGED, MainWindowHook, this);
}
TaskbarTabPreview::~TaskbarTabPreview() {
if (mIcon) {
::DestroyIcon(mIcon);
mIcon = nullptr;
}
// We need to ensure that proxy window disappears or else Bad Things happen.
if (mProxyWindow)
Disable();
NS_ASSERTION(!mProxyWindow, "Taskbar proxy window was not destroyed!");
if (IsWindowAvailable()) {
DetachFromNSWindow();
} else {
mWnd = nullptr;
}
}
nsresult
TaskbarTabPreview::ShowActive(bool active) {
NS_ASSERTION(mVisible && CanMakeTaskbarCalls(), "ShowActive called on invisible window or before taskbar calls can be made for this window");
return FAILED(mTaskbar->SetTabActive(active ? mProxyWindow : nullptr,
mWnd, 0)) ? NS_ERROR_FAILURE : NS_OK;
}
HWND &
TaskbarTabPreview::PreviewWindow() {
return mProxyWindow;
}
nativeWindow
TaskbarTabPreview::GetHWND() {
return mProxyWindow;
}
void
TaskbarTabPreview::EnsureRegistration() {
NS_ASSERTION(mVisible && CanMakeTaskbarCalls(), "EnsureRegistration called when it is not safe to do so");
(void) UpdateTaskbarProperties();
}
NS_IMETHODIMP
TaskbarTabPreview::GetTitle(nsAString &aTitle) {
aTitle = mTitle;
return NS_OK;
}
NS_IMETHODIMP
TaskbarTabPreview::SetTitle(const nsAString &aTitle) {
mTitle = aTitle;
return mVisible ? UpdateTitle() : NS_OK;
}
NS_IMETHODIMP
TaskbarTabPreview::SetIcon(imgIContainer *icon) {
HICON hIcon = nullptr;
if (icon) {
nsresult rv;
rv = nsWindowGfx::CreateIcon(icon, false, 0, 0,
nsWindowGfx::GetIconMetrics(nsWindowGfx::kSmallIcon),
&hIcon);
NS_ENSURE_SUCCESS(rv, rv);
}
if (mIcon)
::DestroyIcon(mIcon);
mIcon = hIcon;
mIconImage = icon;
return mVisible ? UpdateIcon() : NS_OK;
}
NS_IMETHODIMP
TaskbarTabPreview::GetIcon(imgIContainer **icon) {
NS_IF_ADDREF(*icon = mIconImage);
return NS_OK;
}
NS_IMETHODIMP
TaskbarTabPreview::Move(nsITaskbarTabPreview *aNext) {
if (aNext == this)
return NS_ERROR_INVALID_ARG;
mNext = aNext;
return CanMakeTaskbarCalls() ? UpdateNext() : NS_OK;
}
nsresult
TaskbarTabPreview::UpdateTaskbarProperties() {
if (mRegistered)
return NS_OK;
if (FAILED(mTaskbar->RegisterTab(mProxyWindow, mWnd)))
return NS_ERROR_FAILURE;
nsresult rv = UpdateNext();
NS_ENSURE_SUCCESS(rv, rv);
rv = TaskbarPreview::UpdateTaskbarProperties();
mRegistered = true;
return rv;
}
LRESULT
TaskbarTabPreview::WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam) {
RefPtr<TaskbarTabPreview> kungFuDeathGrip(this);
switch (nMsg) {
case WM_CREATE:
TaskbarPreview::EnableCustomDrawing(mProxyWindow, true);
return 0;
case WM_CLOSE:
mController->OnClose();
return 0;
case WM_ACTIVATE:
if (LOWORD(wParam) == WA_ACTIVE) {
// Activate the tab the user selected then restore the main window,
// keeping normal/max window state intact.
bool activateWindow;
nsresult rv = mController->OnActivate(&activateWindow);
if (NS_SUCCEEDED(rv) && activateWindow) {
nsWindow* win = WinUtils::GetNSWindowPtr(mWnd);
if (win) {
nsWindow * parent = win->GetTopLevelWindow(true);
if (parent) {
parent->Show(true);
}
}
}
}
return 0;
case WM_GETICON:
return (LRESULT)mIcon;
case WM_SYSCOMMAND:
// Send activation events to the top level window and select the proper
// tab through the controller.
if (wParam == SC_RESTORE || wParam == SC_MAXIMIZE) {
bool activateWindow;
nsresult rv = mController->OnActivate(&activateWindow);
if (NS_SUCCEEDED(rv) && activateWindow) {
// Note, restoring an iconic, maximized window here will only
// activate the maximized window. This is not a bug, it's default
// windows behavior.
::SendMessageW(mWnd, WM_SYSCOMMAND, wParam, lParam);
}
return 0;
}
// Forward everything else to the top level window. Do not forward
// close since that's intended for the tab. When the preview proxy
// closes, we'll close the tab above.
return wParam == SC_CLOSE
? ::DefWindowProcW(mProxyWindow, WM_SYSCOMMAND, wParam, lParam)
: ::SendMessageW(mWnd, WM_SYSCOMMAND, wParam, lParam);
return 0;
}
return TaskbarPreview::WndProc(nMsg, wParam, lParam);
}
/* static */
LRESULT CALLBACK
TaskbarTabPreview::GlobalWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) {
TaskbarTabPreview *preview(nullptr);
if (nMsg == WM_CREATE) {
CREATESTRUCT *cs = reinterpret_cast<CREATESTRUCT*>(lParam);
preview = reinterpret_cast<TaskbarTabPreview*>(cs->lpCreateParams);
if (!::SetPropW(hWnd, TASKBARPREVIEW_HWNDID, preview))
NS_ERROR("Could not associate native window with tab preview");
preview->mProxyWindow = hWnd;
} else {
preview = reinterpret_cast<TaskbarTabPreview*>(::GetPropW(hWnd, TASKBARPREVIEW_HWNDID));
if (nMsg == WM_DESTROY)
::RemovePropW(hWnd, TASKBARPREVIEW_HWNDID);
}
if (preview)
return preview->WndProc(nMsg, wParam, lParam);
return ::DefWindowProcW(hWnd, nMsg, wParam, lParam);
}
nsresult
TaskbarTabPreview::Enable() {
WNDCLASSW wc;
HINSTANCE module = GetModuleHandle(nullptr);
if (!GetClassInfoW(module, kWindowClass, &wc)) {
wc.style = 0;
wc.lpfnWndProc = GlobalWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = module;
wc.hIcon = nullptr;
wc.hCursor = nullptr;
wc.hbrBackground = (HBRUSH) nullptr;
wc.lpszMenuName = (LPCWSTR) nullptr;
wc.lpszClassName = kWindowClass;
RegisterClassW(&wc);
}
::CreateWindowW(kWindowClass, L"TaskbarPreviewWindow",
WS_CAPTION | WS_SYSMENU, 0, 0, 200, 60,
nullptr, nullptr, module, this);
// GlobalWndProc will set mProxyWindow so that WM_CREATE can have a valid HWND
if (!mProxyWindow)
return NS_ERROR_INVALID_ARG;
UpdateProxyWindowStyle();
nsresult rv = TaskbarPreview::Enable();
nsresult rvUpdate;
rvUpdate = UpdateTitle();
if (NS_FAILED(rvUpdate))
rv = rvUpdate;
rvUpdate = UpdateIcon();
if (NS_FAILED(rvUpdate))
rv = rvUpdate;
return rv;
}
nsresult
TaskbarTabPreview::Disable() {
// TaskbarPreview::Disable assumes that mWnd is valid but this method can be
// called when it is null iff the nsWindow has already been destroyed and we
// are still visible for some reason during object destruction.
if (mWnd)
TaskbarPreview::Disable();
if (FAILED(mTaskbar->UnregisterTab(mProxyWindow)))
return NS_ERROR_FAILURE;
mRegistered = false;
// TaskbarPreview::WndProc will set mProxyWindow to null
if (!DestroyWindow(mProxyWindow))
return NS_ERROR_FAILURE;
mProxyWindow = nullptr;
return NS_OK;
}
void
TaskbarTabPreview::DetachFromNSWindow() {
(void) SetVisible(false);
WindowHook &hook = GetWindowHook();
hook.RemoveMonitor(WM_WINDOWPOSCHANGED, MainWindowHook, this);
TaskbarPreview::DetachFromNSWindow();
}
/* static */
bool
TaskbarTabPreview::MainWindowHook(void *aContext,
HWND hWnd, UINT nMsg,
WPARAM wParam, LPARAM lParam,
LRESULT *aResult) {
if (nMsg == WM_WINDOWPOSCHANGED) {
TaskbarTabPreview *preview = reinterpret_cast<TaskbarTabPreview*>(aContext);
WINDOWPOS *pos = reinterpret_cast<WINDOWPOS*>(lParam);
if (SWP_FRAMECHANGED == (pos->flags & SWP_FRAMECHANGED))
preview->UpdateProxyWindowStyle();
} else {
NS_NOTREACHED("Style changed hook fired on non-style changed message");
}
return false;
}
void
TaskbarTabPreview::UpdateProxyWindowStyle() {
if (!mProxyWindow)
return;
DWORD minMaxMask = WS_MINIMIZE | WS_MAXIMIZE;
DWORD windowStyle = GetWindowLongW(mWnd, GWL_STYLE);
DWORD proxyStyle = GetWindowLongW(mProxyWindow, GWL_STYLE);
proxyStyle &= ~minMaxMask;
proxyStyle |= windowStyle & minMaxMask;
SetWindowLongW(mProxyWindow, GWL_STYLE, proxyStyle);
DWORD exStyle = (WS_MAXIMIZE == (windowStyle & WS_MAXIMIZE)) ? WS_EX_TOOLWINDOW : 0;
SetWindowLongW(mProxyWindow, GWL_EXSTYLE, exStyle);
}
nsresult
TaskbarTabPreview::UpdateTitle() {
NS_ASSERTION(mVisible, "UpdateTitle called on invisible preview");
if (!::SetWindowTextW(mProxyWindow, mTitle.get()))
return NS_ERROR_FAILURE;
return NS_OK;
}
nsresult
TaskbarTabPreview::UpdateIcon() {
NS_ASSERTION(mVisible, "UpdateIcon called on invisible preview");
::SendMessageW(mProxyWindow, WM_SETICON, ICON_SMALL, (LPARAM)mIcon);
return NS_OK;
}
nsresult
TaskbarTabPreview::UpdateNext() {
NS_ASSERTION(CanMakeTaskbarCalls() && mVisible, "UpdateNext called on invisible tab preview");
HWND hNext = nullptr;
if (mNext) {
bool visible;
nsresult rv = mNext->GetVisible(&visible);
NS_ENSURE_SUCCESS(rv, rv);
// Can only move next to enabled previews
if (!visible)
return NS_ERROR_FAILURE;
hNext = (HWND)mNext->GetHWND();
// hNext must be registered with the taskbar if the call is to succeed
mNext->EnsureRegistration();
}
if (FAILED(mTaskbar->SetTabOrder(mProxyWindow, hNext)))
return NS_ERROR_FAILURE;
return NS_OK;
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,70 @@
/* vim: se cin sw=2 ts=2 et : */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __mozilla_widget_TaskbarTabPreview_h__
#define __mozilla_widget_TaskbarTabPreview_h__
#include "nsITaskbarTabPreview.h"
#include "TaskbarPreview.h"
namespace mozilla {
namespace widget {
class TaskbarTabPreview : public nsITaskbarTabPreview,
public TaskbarPreview
{
virtual ~TaskbarTabPreview();
public:
TaskbarTabPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell);
NS_DECL_ISUPPORTS
NS_DECL_NSITASKBARTABPREVIEW
NS_FORWARD_NSITASKBARPREVIEW(TaskbarPreview::)
private:
virtual nsresult ShowActive(bool active);
virtual HWND &PreviewWindow();
virtual LRESULT WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK GlobalWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam);
virtual nsresult UpdateTaskbarProperties();
virtual nsresult Enable();
virtual nsresult Disable();
virtual void DetachFromNSWindow();
// WindowHook procedure for hooking mWnd
static bool MainWindowHook(void *aContext,
HWND hWnd, UINT nMsg,
WPARAM wParam, LPARAM lParam,
LRESULT *aResult);
// Bug 520807 - we need to update the proxy window style based on the main
// window's style to workaround a bug with the way the DWM displays the
// previews.
void UpdateProxyWindowStyle();
nsresult UpdateTitle();
nsresult UpdateIcon();
nsresult UpdateNext();
// Handle to the toplevel proxy window
HWND mProxyWindow;
nsString mTitle;
nsCOMPtr<imgIContainer> mIconImage;
// Cached Windows icon of mIconImage
HICON mIcon;
// Preview that follows this preview in the taskbar (left-to-right order)
nsCOMPtr<nsITaskbarTabPreview> mNext;
// True if this preview has been registered with the taskbar
bool mRegistered;
};
} // namespace widget
} // namespace mozilla
#endif /* __mozilla_widget_TaskbarTabPreview_h__ */

View file

@ -0,0 +1,326 @@
/* vim: se cin sw=2 ts=2 et : */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/ArrayUtils.h"
#include <nsITaskbarPreviewController.h>
#include "TaskbarWindowPreview.h"
#include "WindowHook.h"
#include "nsUXThemeData.h"
#include "TaskbarPreviewButton.h"
#include "nsWindow.h"
#include "nsWindowGfx.h"
namespace mozilla {
namespace widget {
namespace {
bool WindowHookProc(void *aContext, HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, LRESULT *aResult)
{
TaskbarWindowPreview *preview = reinterpret_cast<TaskbarWindowPreview*>(aContext);
*aResult = preview->WndProc(nMsg, wParam, lParam);
return true;
}
}
NS_IMPL_ISUPPORTS(TaskbarWindowPreview, nsITaskbarWindowPreview,
nsITaskbarProgress, nsITaskbarOverlayIconController,
nsISupportsWeakReference)
/**
* These correspond directly to the states defined in nsITaskbarProgress.idl, so
* they should be kept in sync.
*/
static TBPFLAG sNativeStates[] =
{
TBPF_NOPROGRESS,
TBPF_INDETERMINATE,
TBPF_NORMAL,
TBPF_ERROR,
TBPF_PAUSED
};
TaskbarWindowPreview::TaskbarWindowPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell)
: TaskbarPreview(aTaskbar, aController, aHWND, aShell),
mCustomDrawing(false),
mHaveButtons(false),
mState(TBPF_NOPROGRESS),
mCurrentValue(0),
mMaxValue(0),
mOverlayIcon(nullptr)
{
// Window previews are visible by default
(void) SetVisible(true);
memset(mThumbButtons, 0, sizeof mThumbButtons);
for (int32_t i = 0; i < nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS; i++) {
mThumbButtons[i].dwMask = THB_FLAGS | THB_ICON | THB_TOOLTIP;
mThumbButtons[i].iId = i;
mThumbButtons[i].dwFlags = THBF_HIDDEN;
}
WindowHook &hook = GetWindowHook();
if (!CanMakeTaskbarCalls())
hook.AddMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(),
TaskbarWindowHook, this);
}
TaskbarWindowPreview::~TaskbarWindowPreview() {
if (mOverlayIcon) {
::DestroyIcon(mOverlayIcon);
mOverlayIcon = nullptr;
}
if (IsWindowAvailable()) {
DetachFromNSWindow();
} else {
mWnd = nullptr;
}
}
nsresult
TaskbarWindowPreview::ShowActive(bool active) {
return FAILED(mTaskbar->ActivateTab(active ? mWnd : nullptr))
? NS_ERROR_FAILURE
: NS_OK;
}
HWND &
TaskbarWindowPreview::PreviewWindow() {
return mWnd;
}
nsresult
TaskbarWindowPreview::GetButton(uint32_t index, nsITaskbarPreviewButton **_retVal) {
if (index >= nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS)
return NS_ERROR_INVALID_ARG;
nsCOMPtr<nsITaskbarPreviewButton> button(do_QueryReferent(mWeakButtons[index]));
if (!button) {
// Lost reference
button = new TaskbarPreviewButton(this, index);
if (!button) {
return NS_ERROR_OUT_OF_MEMORY;
}
mWeakButtons[index] = do_GetWeakReference(button);
}
if (!mHaveButtons) {
mHaveButtons = true;
WindowHook &hook = GetWindowHook();
(void) hook.AddHook(WM_COMMAND, WindowHookProc, this);
if (mVisible && FAILED(mTaskbar->ThumbBarAddButtons(mWnd, nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS, mThumbButtons))) {
return NS_ERROR_FAILURE;
}
}
button.forget(_retVal);
return NS_OK;
}
NS_IMETHODIMP
TaskbarWindowPreview::SetEnableCustomDrawing(bool aEnable) {
if (aEnable == mCustomDrawing)
return NS_OK;
mCustomDrawing = aEnable;
TaskbarPreview::EnableCustomDrawing(mWnd, aEnable);
WindowHook &hook = GetWindowHook();
if (aEnable) {
(void) hook.AddHook(WM_DWMSENDICONICTHUMBNAIL, WindowHookProc, this);
(void) hook.AddHook(WM_DWMSENDICONICLIVEPREVIEWBITMAP, WindowHookProc, this);
} else {
(void) hook.RemoveHook(WM_DWMSENDICONICLIVEPREVIEWBITMAP, WindowHookProc, this);
(void) hook.RemoveHook(WM_DWMSENDICONICTHUMBNAIL, WindowHookProc, this);
}
return NS_OK;
}
NS_IMETHODIMP
TaskbarWindowPreview::GetEnableCustomDrawing(bool *aEnable) {
*aEnable = mCustomDrawing;
return NS_OK;
}
NS_IMETHODIMP
TaskbarWindowPreview::SetProgressState(nsTaskbarProgressState aState,
uint64_t aCurrentValue,
uint64_t aMaxValue)
{
NS_ENSURE_ARG_RANGE(aState,
nsTaskbarProgressState(0),
nsTaskbarProgressState(ArrayLength(sNativeStates) - 1));
TBPFLAG nativeState = sNativeStates[aState];
if (nativeState == TBPF_NOPROGRESS || nativeState == TBPF_INDETERMINATE) {
NS_ENSURE_TRUE(aCurrentValue == 0, NS_ERROR_INVALID_ARG);
NS_ENSURE_TRUE(aMaxValue == 0, NS_ERROR_INVALID_ARG);
}
if (aCurrentValue > aMaxValue)
return NS_ERROR_ILLEGAL_VALUE;
mState = nativeState;
mCurrentValue = aCurrentValue;
mMaxValue = aMaxValue;
// Only update if we can
return CanMakeTaskbarCalls() ? UpdateTaskbarProgress() : NS_OK;
}
NS_IMETHODIMP
TaskbarWindowPreview::SetOverlayIcon(imgIContainer* aStatusIcon,
const nsAString& aStatusDescription) {
nsresult rv;
if (aStatusIcon) {
// The image shouldn't be animated
bool isAnimated;
rv = aStatusIcon->GetAnimated(&isAnimated);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_FALSE(isAnimated, NS_ERROR_INVALID_ARG);
}
HICON hIcon = nullptr;
if (aStatusIcon) {
rv = nsWindowGfx::CreateIcon(aStatusIcon, false, 0, 0,
nsWindowGfx::GetIconMetrics(nsWindowGfx::kSmallIcon),
&hIcon);
NS_ENSURE_SUCCESS(rv, rv);
}
if (mOverlayIcon)
::DestroyIcon(mOverlayIcon);
mOverlayIcon = hIcon;
mIconDescription = aStatusDescription;
// Only update if we can
return CanMakeTaskbarCalls() ? UpdateOverlayIcon() : NS_OK;
}
nsresult
TaskbarWindowPreview::UpdateTaskbarProperties() {
if (mHaveButtons) {
if (FAILED(mTaskbar->ThumbBarAddButtons(mWnd, nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS, mThumbButtons)))
return NS_ERROR_FAILURE;
}
nsresult rv = UpdateTaskbarProgress();
NS_ENSURE_SUCCESS(rv, rv);
rv = UpdateOverlayIcon();
NS_ENSURE_SUCCESS(rv, rv);
return TaskbarPreview::UpdateTaskbarProperties();
}
nsresult
TaskbarWindowPreview::UpdateTaskbarProgress() {
HRESULT hr = mTaskbar->SetProgressState(mWnd, mState);
if (SUCCEEDED(hr) && mState != TBPF_NOPROGRESS &&
mState != TBPF_INDETERMINATE)
hr = mTaskbar->SetProgressValue(mWnd, mCurrentValue, mMaxValue);
return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
}
nsresult
TaskbarWindowPreview::UpdateOverlayIcon() {
HRESULT hr = mTaskbar->SetOverlayIcon(mWnd, mOverlayIcon,
mIconDescription.get());
return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
}
LRESULT
TaskbarWindowPreview::WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam) {
RefPtr<TaskbarWindowPreview> kungFuDeathGrip(this);
switch (nMsg) {
case WM_COMMAND:
{
uint32_t id = LOWORD(wParam);
uint32_t index = id;
nsCOMPtr<nsITaskbarPreviewButton> button;
nsresult rv = GetButton(index, getter_AddRefs(button));
if (NS_SUCCEEDED(rv))
mController->OnClick(button);
}
return 0;
}
return TaskbarPreview::WndProc(nMsg, wParam, lParam);
}
/* static */
bool
TaskbarWindowPreview::TaskbarWindowHook(void *aContext,
HWND hWnd, UINT nMsg,
WPARAM wParam, LPARAM lParam,
LRESULT *aResult)
{
NS_ASSERTION(nMsg == nsAppShell::GetTaskbarButtonCreatedMessage(),
"Window hook proc called with wrong message");
TaskbarWindowPreview *preview =
reinterpret_cast<TaskbarWindowPreview*>(aContext);
// Now we can make all the calls to mTaskbar
preview->UpdateTaskbarProperties();
return false;
}
nsresult
TaskbarWindowPreview::Enable() {
nsresult rv = TaskbarPreview::Enable();
NS_ENSURE_SUCCESS(rv, rv);
return FAILED(mTaskbar->AddTab(mWnd))
? NS_ERROR_FAILURE
: NS_OK;
}
nsresult
TaskbarWindowPreview::Disable() {
nsresult rv = TaskbarPreview::Disable();
NS_ENSURE_SUCCESS(rv, rv);
return FAILED(mTaskbar->DeleteTab(mWnd))
? NS_ERROR_FAILURE
: NS_OK;
}
void
TaskbarWindowPreview::DetachFromNSWindow() {
// Remove the hooks we have for drawing
SetEnableCustomDrawing(false);
WindowHook &hook = GetWindowHook();
(void) hook.RemoveHook(WM_COMMAND, WindowHookProc, this);
(void) hook.RemoveMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(),
TaskbarWindowHook, this);
TaskbarPreview::DetachFromNSWindow();
}
nsresult
TaskbarWindowPreview::UpdateButtons() {
NS_ASSERTION(mVisible, "UpdateButtons called on invisible preview");
if (FAILED(mTaskbar->ThumbBarUpdateButtons(mWnd, nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS, mThumbButtons)))
return NS_ERROR_FAILURE;
return NS_OK;
}
nsresult
TaskbarWindowPreview::UpdateButton(uint32_t index) {
if (index >= nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS)
return NS_ERROR_INVALID_ARG;
if (mVisible) {
if (FAILED(mTaskbar->ThumbBarUpdateButtons(mWnd, 1, &mThumbButtons[index])))
return NS_ERROR_FAILURE;
}
return NS_OK;
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,85 @@
/* vim: se cin sw=2 ts=2 et : */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __mozilla_widget_TaskbarWindowPreview_h__
#define __mozilla_widget_TaskbarWindowPreview_h__
#include "nsITaskbarWindowPreview.h"
#include "nsITaskbarProgress.h"
#include "nsITaskbarOverlayIconController.h"
#include "TaskbarPreview.h"
#include <nsWeakReference.h>
namespace mozilla {
namespace widget {
class TaskbarPreviewButton;
class TaskbarWindowPreview : public TaskbarPreview,
public nsITaskbarWindowPreview,
public nsITaskbarProgress,
public nsITaskbarOverlayIconController,
public nsSupportsWeakReference
{
virtual ~TaskbarWindowPreview();
public:
TaskbarWindowPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell);
NS_DECL_ISUPPORTS
NS_DECL_NSITASKBARWINDOWPREVIEW
NS_DECL_NSITASKBARPROGRESS
NS_DECL_NSITASKBAROVERLAYICONCONTROLLER
NS_FORWARD_NSITASKBARPREVIEW(TaskbarPreview::)
virtual LRESULT WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam) override;
private:
virtual nsresult ShowActive(bool active) override;
virtual HWND &PreviewWindow() override;
virtual nsresult UpdateTaskbarProperties() override;
virtual nsresult Enable() override;
virtual nsresult Disable() override;
virtual void DetachFromNSWindow() override;
nsresult UpdateButton(uint32_t index);
nsresult UpdateButtons();
// Is custom drawing enabled?
bool mCustomDrawing;
// Have we made any buttons?
bool mHaveButtons;
// Windows button format
THUMBBUTTON mThumbButtons[nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS];
// Pointers to our button class (cached instances)
nsWeakPtr mWeakButtons[nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS];
// Called to update ITaskbarList4 dependent properties
nsresult UpdateTaskbarProgress();
nsresult UpdateOverlayIcon();
// The taskbar progress
TBPFLAG mState;
ULONGLONG mCurrentValue;
ULONGLONG mMaxValue;
// Taskbar overlay icon
HICON mOverlayIcon;
nsString mIconDescription;
// WindowHook procedure for hooking mWnd for taskbar progress and icon stuff
static bool TaskbarWindowHook(void *aContext,
HWND hWnd, UINT nMsg,
WPARAM wParam, LPARAM lParam,
LRESULT *aResult);
friend class TaskbarPreviewButton;
};
} // namespace widget
} // namespace mozilla
#endif /* __mozilla_widget_TaskbarWindowPreview_h__ */

View file

@ -0,0 +1,132 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Windows widget support for event loop instrumentation.
* See toolkit/xre/EventTracer.cpp for more details.
*/
#include <stdio.h>
#include <windows.h>
#include "mozilla/RefPtr.h"
#include "mozilla/WidgetTraceEvent.h"
#include "nsAppShellCID.h"
#include "nsComponentManagerUtils.h"
#include "nsCOMPtr.h"
#include "nsIAppShellService.h"
#include "nsIBaseWindow.h"
#include "nsIDocShell.h"
#include "nsISupportsImpl.h"
#include "nsIWidget.h"
#include "nsIXULWindow.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
#include "nsWindowDefs.h"
namespace {
// Used for signaling the background thread from the main thread.
HANDLE sEventHandle = nullptr;
// We need a runnable in order to find the hidden window on the main
// thread.
class HWNDGetter : public mozilla::Runnable {
public:
HWNDGetter() : hidden_window_hwnd(nullptr) {
MOZ_COUNT_CTOR(HWNDGetter);
}
~HWNDGetter() {
MOZ_COUNT_DTOR(HWNDGetter);
}
HWND hidden_window_hwnd;
NS_IMETHOD Run() override {
// Jump through some hoops to locate the hidden window.
nsCOMPtr<nsIAppShellService> appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
nsCOMPtr<nsIXULWindow> hiddenWindow;
nsresult rv = appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow));
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsIDocShell> docShell;
rv = hiddenWindow->GetDocShell(getter_AddRefs(docShell));
if (NS_FAILED(rv) || !docShell) {
return rv;
}
nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(docShell));
if (!baseWindow)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIWidget> widget;
baseWindow->GetMainWidget(getter_AddRefs(widget));
if (!widget)
return NS_ERROR_FAILURE;
hidden_window_hwnd = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW);
return NS_OK;
}
};
HWND GetHiddenWindowHWND()
{
// Need to dispatch this to the main thread because plenty of
// the things it wants to access are main-thread-only.
RefPtr<HWNDGetter> getter = new HWNDGetter();
NS_DispatchToMainThread(getter, NS_DISPATCH_SYNC);
return getter->hidden_window_hwnd;
}
} // namespace
namespace mozilla {
bool InitWidgetTracing()
{
sEventHandle = CreateEventW(nullptr, FALSE, FALSE, nullptr);
return sEventHandle != nullptr;
}
void CleanUpWidgetTracing()
{
CloseHandle(sEventHandle);
sEventHandle = nullptr;
}
// This function is called from the main (UI) thread.
void SignalTracerThread()
{
if (sEventHandle != nullptr)
SetEvent(sEventHandle);
}
// This function is called from the background tracer thread.
bool FireAndWaitForTracerEvent()
{
MOZ_ASSERT(sEventHandle, "Tracing not initialized!");
// First, try to find the hidden window.
static HWND hidden_window = nullptr;
if (hidden_window == nullptr) {
hidden_window = GetHiddenWindowHWND();
}
if (hidden_window == nullptr)
return false;
// Post the tracer message into the hidden window's message queue,
// and then block until it's processed.
PostMessage(hidden_window, MOZ_WM_TRACE, 0, 0);
WaitForSingleObject(sEventHandle, INFINITE);
return true;
}
} // namespace mozilla

View file

@ -0,0 +1,329 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WinCompositorWidget.h"
#include "gfxPrefs.h"
#include "mozilla/gfx/DeviceManagerDx.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/layers/Compositor.h"
#include "mozilla/widget/PlatformWidgetTypes.h"
#include "nsWindow.h"
#include "VsyncDispatcher.h"
#include <ddraw.h>
namespace mozilla {
namespace widget {
using namespace mozilla::gfx;
WinCompositorWidget::WinCompositorWidget(const CompositorWidgetInitData& aInitData)
: mWidgetKey(aInitData.widgetKey()),
mWnd(reinterpret_cast<HWND>(aInitData.hWnd())),
mTransparencyMode(static_cast<nsTransparencyMode>(aInitData.transparencyMode())),
mMemoryDC(nullptr),
mCompositeDC(nullptr),
mLockedBackBufferData(nullptr)
{
MOZ_ASSERT(mWnd && ::IsWindow(mWnd));
// mNotDeferEndRemoteDrawing is set on the main thread during init,
// but is only accessed after on the compositor thread.
mNotDeferEndRemoteDrawing = gfxPrefs::LayersCompositionFrameRate() == 0 ||
gfxPlatform::IsInLayoutAsapMode() ||
gfxPlatform::ForceSoftwareVsync();
}
void
WinCompositorWidget::OnDestroyWindow()
{
mTransparentSurface = nullptr;
mMemoryDC = nullptr;
}
bool
WinCompositorWidget::PreRender(WidgetRenderingContext* aContext)
{
// This can block waiting for WM_SETTEXT to finish
// Using PreRender is unnecessarily pessimistic because
// we technically only need to block during the present call
// not all of compositor rendering
mPresentLock.Enter();
return true;
}
void
WinCompositorWidget::PostRender(WidgetRenderingContext* aContext)
{
mPresentLock.Leave();
}
LayoutDeviceIntSize
WinCompositorWidget::GetClientSize()
{
RECT r;
if (!::GetClientRect(mWnd, &r)) {
return LayoutDeviceIntSize();
}
return LayoutDeviceIntSize(
r.right - r.left,
r.bottom - r.top);
}
already_AddRefed<gfx::DrawTarget>
WinCompositorWidget::StartRemoteDrawing()
{
MOZ_ASSERT(!mCompositeDC);
RefPtr<gfxASurface> surf;
if (mTransparencyMode == eTransparencyTransparent) {
surf = EnsureTransparentSurface();
}
// Must call this after EnsureTransparentSurface(), since it could update
// the DC.
HDC dc = GetWindowSurface();
if (!surf) {
if (!dc) {
return nullptr;
}
uint32_t flags = (mTransparencyMode == eTransparencyOpaque) ? 0 :
gfxWindowsSurface::FLAG_IS_TRANSPARENT;
surf = new gfxWindowsSurface(dc, flags);
}
IntSize size = surf->GetSize();
if (size.width <= 0 || size.height <= 0) {
if (dc) {
FreeWindowSurface(dc);
}
return nullptr;
}
MOZ_ASSERT(!mCompositeDC);
mCompositeDC = dc;
return mozilla::gfx::Factory::CreateDrawTargetForCairoSurface(surf->CairoSurface(), size);
}
void
WinCompositorWidget::EndRemoteDrawing()
{
MOZ_ASSERT(!mLockedBackBufferData);
if (mTransparencyMode == eTransparencyTransparent) {
MOZ_ASSERT(mTransparentSurface);
RedrawTransparentWindow();
}
if (mCompositeDC) {
FreeWindowSurface(mCompositeDC);
}
mCompositeDC = nullptr;
}
bool
WinCompositorWidget::NeedsToDeferEndRemoteDrawing()
{
if(mNotDeferEndRemoteDrawing) {
return false;
}
IDirectDraw7* ddraw = DeviceManagerDx::Get()->GetDirectDraw();
if (!ddraw) {
return false;
}
DWORD scanLine = 0;
int height = ::GetSystemMetrics(SM_CYSCREEN);
HRESULT ret = ddraw->GetScanLine(&scanLine);
if (ret == DDERR_VERTICALBLANKINPROGRESS) {
scanLine = 0;
} else if (ret != DD_OK) {
return false;
}
// Check if there is a risk of tearing with GDI.
if (static_cast<int>(scanLine) > height / 2) {
// No need to defer.
return false;
}
return true;
}
already_AddRefed<gfx::DrawTarget>
WinCompositorWidget::GetBackBufferDrawTarget(gfx::DrawTarget* aScreenTarget,
const LayoutDeviceIntRect& aRect,
const LayoutDeviceIntRect& aClearRect)
{
MOZ_ASSERT(!mLockedBackBufferData);
RefPtr<gfx::DrawTarget> target =
CompositorWidget::GetBackBufferDrawTarget(aScreenTarget, aRect, aClearRect);
if (!target) {
return nullptr;
}
MOZ_ASSERT(target->GetBackendType() == BackendType::CAIRO);
uint8_t* destData;
IntSize destSize;
int32_t destStride;
SurfaceFormat destFormat;
if (!target->LockBits(&destData, &destSize, &destStride, &destFormat)) {
// LockBits is not supported. Use original DrawTarget.
return target.forget();
}
RefPtr<gfx::DrawTarget> dataTarget =
Factory::CreateDrawTargetForData(BackendType::CAIRO,
destData,
destSize,
destStride,
destFormat);
mLockedBackBufferData = destData;
return dataTarget.forget();
}
already_AddRefed<gfx::SourceSurface>
WinCompositorWidget::EndBackBufferDrawing()
{
if (mLockedBackBufferData) {
MOZ_ASSERT(mLastBackBuffer);
mLastBackBuffer->ReleaseBits(mLockedBackBufferData);
mLockedBackBufferData = nullptr;
}
return CompositorWidget::EndBackBufferDrawing();
}
bool
WinCompositorWidget::InitCompositor(layers::Compositor* aCompositor)
{
if (aCompositor->GetBackendType() == layers::LayersBackend::LAYERS_BASIC) {
DeviceManagerDx::Get()->InitializeDirectDraw();
}
return true;
}
uintptr_t
WinCompositorWidget::GetWidgetKey()
{
return mWidgetKey;
}
void
WinCompositorWidget::EnterPresentLock()
{
mPresentLock.Enter();
}
void
WinCompositorWidget::LeavePresentLock()
{
mPresentLock.Leave();
}
RefPtr<gfxASurface>
WinCompositorWidget::EnsureTransparentSurface()
{
MOZ_ASSERT(mTransparencyMode == eTransparencyTransparent);
IntSize size = GetClientSize().ToUnknownSize();
if (!mTransparentSurface || mTransparentSurface->GetSize() != size) {
mTransparentSurface = nullptr;
mMemoryDC = nullptr;
CreateTransparentSurface(size);
}
RefPtr<gfxASurface> surface = mTransparentSurface;
return surface.forget();
}
void
WinCompositorWidget::CreateTransparentSurface(const gfx::IntSize& aSize)
{
MOZ_ASSERT(!mTransparentSurface && !mMemoryDC);
RefPtr<gfxWindowsSurface> surface = new gfxWindowsSurface(aSize, SurfaceFormat::A8R8G8B8_UINT32);
mTransparentSurface = surface;
mMemoryDC = surface->GetDC();
}
void
WinCompositorWidget::UpdateTransparency(nsTransparencyMode aMode)
{
if (mTransparencyMode == aMode) {
return;
}
mTransparencyMode = aMode;
mTransparentSurface = nullptr;
mMemoryDC = nullptr;
if (mTransparencyMode == eTransparencyTransparent) {
EnsureTransparentSurface();
}
}
void
WinCompositorWidget::ClearTransparentWindow()
{
if (!mTransparentSurface) {
return;
}
EnsureTransparentSurface();
IntSize size = mTransparentSurface->GetSize();
if (!size.IsEmpty()) {
RefPtr<DrawTarget> drawTarget =
gfxPlatform::CreateDrawTargetForSurface(mTransparentSurface, size);
if (!drawTarget) {
return;
}
drawTarget->ClearRect(Rect(0, 0, size.width, size.height));
RedrawTransparentWindow();
}
}
bool
WinCompositorWidget::RedrawTransparentWindow()
{
MOZ_ASSERT(mTransparencyMode == eTransparencyTransparent);
LayoutDeviceIntSize size = GetClientSize();
::GdiFlush();
BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
SIZE winSize = { size.width, size.height };
POINT srcPos = { 0, 0 };
HWND hWnd = WinUtils::GetTopLevelHWND(mWnd, true);
RECT winRect;
::GetWindowRect(hWnd, &winRect);
// perform the alpha blend
return !!::UpdateLayeredWindow(
hWnd, nullptr, (POINT*)&winRect, &winSize, mMemoryDC,
&srcPos, 0, &bf, ULW_ALPHA);
}
HDC
WinCompositorWidget::GetWindowSurface()
{
return eTransparencyTransparent == mTransparencyMode
? mMemoryDC
: ::GetDC(mWnd);
}
void
WinCompositorWidget::FreeWindowSurface(HDC dc)
{
if (eTransparencyTransparent != mTransparencyMode)
::ReleaseDC(mWnd, dc);
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,112 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef widget_windows_CompositorWidgetParent_h
#define widget_windows_CompositorWidgetParent_h
#include "CompositorWidget.h"
#include "gfxASurface.h"
#include "mozilla/gfx/CriticalSection.h"
#include "mozilla/gfx/Point.h"
#include "nsIWidget.h"
class nsWindow;
namespace mozilla {
namespace widget {
class CompositorWidgetDelegate
{
public:
// Callbacks for nsWindow.
virtual void EnterPresentLock() = 0;
virtual void LeavePresentLock() = 0;
virtual void OnDestroyWindow() = 0;
// Transparency handling.
virtual void UpdateTransparency(nsTransparencyMode aMode) = 0;
virtual void ClearTransparentWindow() = 0;
// If in-process and using software rendering, return the backing transparent
// DC.
virtual HDC GetTransparentDC() const = 0;
};
// This is the Windows-specific implementation of CompositorWidget. For
// the most part it only requires an HWND, however it maintains extra state
// for transparent windows, as well as for synchronizing WM_SETTEXT messages
// with the compositor.
class WinCompositorWidget
: public CompositorWidget,
public CompositorWidgetDelegate
{
public:
WinCompositorWidget(const CompositorWidgetInitData& aInitData);
bool PreRender(WidgetRenderingContext*) override;
void PostRender(WidgetRenderingContext*) override;
already_AddRefed<gfx::DrawTarget> StartRemoteDrawing() override;
void EndRemoteDrawing() override;
bool NeedsToDeferEndRemoteDrawing() override;
LayoutDeviceIntSize GetClientSize() override;
already_AddRefed<gfx::DrawTarget> GetBackBufferDrawTarget(gfx::DrawTarget* aScreenTarget,
const LayoutDeviceIntRect& aRect,
const LayoutDeviceIntRect& aClearRect) override;
already_AddRefed<gfx::SourceSurface> EndBackBufferDrawing() override;
bool InitCompositor(layers::Compositor* aCompositor) override;
uintptr_t GetWidgetKey() override;
WinCompositorWidget* AsWindows() override {
return this;
}
CompositorWidgetDelegate* AsDelegate() override {
return this;
}
// CompositorWidgetDelegate overrides.
void EnterPresentLock() override;
void LeavePresentLock() override;
void OnDestroyWindow() override;
void UpdateTransparency(nsTransparencyMode aMode) override;
void ClearTransparentWindow() override;
bool RedrawTransparentWindow();
// Ensure that a transparent surface exists, then return it.
RefPtr<gfxASurface> EnsureTransparentSurface();
HDC GetTransparentDC() const override {
return mMemoryDC;
}
HWND GetHwnd() const {
return mWnd;
}
private:
HDC GetWindowSurface();
void FreeWindowSurface(HDC dc);
void CreateTransparentSurface(const gfx::IntSize& aSize);
private:
uintptr_t mWidgetKey;
HWND mWnd;
gfx::CriticalSection mPresentLock;
// Transparency handling.
nsTransparencyMode mTransparencyMode;
RefPtr<gfxASurface> mTransparentSurface;
HDC mMemoryDC;
HDC mCompositeDC;
// Locked back buffer of BasicCompositor
uint8_t* mLockedBackBufferData;
bool mNotDeferEndRemoteDrawing;
};
} // namespace widget
} // namespace mozilla
#endif // widget_windows_CompositorWidgetParent_h

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,190 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef WinIMEHandler_h_
#define WinIMEHandler_h_
#include "nscore.h"
#include "nsWindowBase.h"
#include "npapi.h"
#include <windows.h>
#include <inputscope.h>
#define NS_WM_IMEFIRST WM_IME_SETCONTEXT
#define NS_WM_IMELAST WM_IME_KEYUP
class nsWindow;
namespace mozilla {
namespace widget {
struct MSGResult;
/**
* IMEHandler class is a mediator class. On Windows, there are two IME API
* sets: One is IMM which is legacy API set. The other is TSF which is modern
* API set. By using this class, non-IME handler classes don't need to worry
* that we're in which mode.
*/
class IMEHandler final
{
public:
static void Initialize();
static void Terminate();
/**
* Returns TSF related native data or native IME context.
*/
static void* GetNativeData(nsWindow* aWindow, uint32_t aDataType);
/**
* ProcessRawKeyMessage() message is called before calling TranslateMessage()
* and DispatchMessage(). If this returns true, the message is consumed.
* Then, caller must not perform TranslateMessage() nor DispatchMessage().
*/
static bool ProcessRawKeyMessage(const MSG& aMsg);
/**
* When the message is not needed to handle anymore by the caller, this
* returns true. Otherwise, false.
*/
static bool ProcessMessage(nsWindow* aWindow, UINT aMessage,
WPARAM& aWParam, LPARAM& aLParam,
MSGResult& aResult);
/**
* When there is a composition, returns true. Otherwise, false.
*/
static bool IsComposing();
/**
* When there is a composition and it's in the window, returns true.
* Otherwise, false.
*/
static bool IsComposingOn(nsWindow* aWindow);
/**
* Notifies IME of the notification (a request or an event).
*/
static nsresult NotifyIME(nsWindow* aWindow,
const IMENotification& aIMENotification);
/**
* Returns update preferences.
*/
static nsIMEUpdatePreference GetUpdatePreference();
/**
* Returns native text event dispatcher listener.
*/
static TextEventDispatcherListener* GetNativeTextEventDispatcherListener();
/**
* Returns IME open state on the window.
*/
static bool GetOpenState(nsWindow* aWindow);
/**
* Called when the window is destroying.
*/
static void OnDestroyWindow(nsWindow* aWindow);
/**
* Called when nsIWidget::SetInputContext() is called before the window's
* InputContext is modified actually.
*/
static void SetInputContext(nsWindow* aWindow,
InputContext& aInputContext,
const InputContextAction& aAction);
/**
* Associate or disassociate IME context to/from the aWindowBase.
*/
static void AssociateIMEContext(nsWindowBase* aWindowBase, bool aEnable);
/**
* Called when the window is created.
*/
static void InitInputContext(nsWindow* aWindow, InputContext& aInputContext);
/*
* For windowless plugin helper.
*/
static void SetCandidateWindow(nsWindow* aWindow, CANDIDATEFORM* aForm);
/*
* For WM_IME_*COMPOSITION messages and e10s with windowless plugin
*/
static void DefaultProcOfPluginEvent(nsWindow* aWindow,
const NPEvent* aPluginEvent);
#ifdef NS_ENABLE_TSF
/**
* This is called by TSFStaticSink when active IME is changed.
*/
static void OnKeyboardLayoutChanged();
#endif // #ifdef NS_ENABLE_TSF
#ifdef DEBUG
/**
* Returns true when current keyboard layout has IME. Otherwise, false.
*/
static bool CurrentKeyboardLayoutHasIME();
#endif // #ifdef DEBUG
private:
static nsWindow* sFocusedWindow;
static InputContextAction::Cause sLastContextActionCause;
static bool sPluginHasFocus;
#ifdef NS_ENABLE_TSF
static decltype(SetInputScopes)* sSetInputScopes;
static void SetInputScopeForIMM32(nsWindow* aWindow,
const nsAString& aHTMLInputType,
const nsAString& aHTMLInputInputmode);
static bool sIsInTSFMode;
// If sIMMEnabled is false, any IME messages are not handled in TSF mode.
// Additionally, IME context is always disassociated from focused window.
static bool sIsIMMEnabled;
static bool sAssociateIMCOnlyWhenIMM_IMEActive;
static bool IsTSFAvailable() { return (sIsInTSFMode && !sPluginHasFocus); }
static bool IsIMMActive();
static void MaybeShowOnScreenKeyboard();
static void MaybeDismissOnScreenKeyboard(nsWindow* aWindow);
static bool WStringStartsWithCaseInsensitive(const std::wstring& aHaystack,
const std::wstring& aNeedle);
static bool NeedOnScreenKeyboard();
static bool IsKeyboardPresentOnSlate();
static bool IsInTabletMode();
static bool AutoInvokeOnScreenKeyboardInDesktopMode();
static bool NeedsToAssociateIMC();
/**
* Show the Windows on-screen keyboard. Only allowed for
* chrome documents and Windows 8 and higher.
*/
static void ShowOnScreenKeyboard();
/**
* Dismiss the Windows on-screen keyboard. Only allowed for
* Windows 8 and higher.
*/
static void DismissOnScreenKeyboard();
/**
* Get the HWND for the on-screen keyboard, if it's up. Only
* allowed for Windows 8 and higher.
*/
static HWND GetOnScreenKeyboardWindow();
#endif // #ifdef NS_ENABLE_TSF
};
} // namespace widget
} // namespace mozilla
#endif // #ifndef WinIMEHandler_h_

View file

@ -0,0 +1,187 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_widget_WinMessages_h_
#define mozilla_widget_WinMessages_h_
/*****************************************************************************
* MOZ_WM_* messages
****************************************************************************/
// A magic APP message that can be sent to quit, sort of like a
// QUERYENDSESSION/ENDSESSION, but without the query.
#define MOZ_WM_APP_QUIT (WM_APP+0x0300)
// Used as a "tracer" event to probe event loop latency.
#define MOZ_WM_TRACE (WM_APP+0x0301)
// Our internal message for WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_VSCROLL and
// WM_HSCROLL
#define MOZ_WM_MOUSEVWHEEL (WM_APP+0x0310)
#define MOZ_WM_MOUSEHWHEEL (WM_APP+0x0311)
#define MOZ_WM_VSCROLL (WM_APP+0x0312)
#define MOZ_WM_HSCROLL (WM_APP+0x0313)
#define MOZ_WM_MOUSEWHEEL_FIRST MOZ_WM_MOUSEVWHEEL
#define MOZ_WM_MOUSEWHEEL_LAST MOZ_WM_HSCROLL
// If a popup window is being activated, we try to reactivate the previous
// window with this message.
#define MOZ_WM_REACTIVATE (WM_APP+0x0314)
// If TSFTextStore needs to notify TSF/TIP of layout change later, this
// message is posted.
#define MOZ_WM_NOTIY_TSF_OF_LAYOUT_CHANGE (WM_APP+0x0315)
// Internal message used in correcting backwards clock skew
#define MOZ_WM_SKEWFIX (WM_APP+0x0316)
// Internal message used for hiding the on-screen keyboard
#define MOZ_WM_DISMISS_ONSCREEN_KEYBOARD (WM_APP+0x0317)
// Following MOZ_WM_*KEY* messages are used by PluginInstanceChild and
// NativeKey internally. (never posted to the queue)
#define MOZ_WM_KEYDOWN (WM_APP+0x0318)
#define MOZ_WM_KEYUP (WM_APP+0x0319)
#define MOZ_WM_SYSKEYDOWN (WM_APP+0x031A)
#define MOZ_WM_SYSKEYUP (WM_APP+0x031B)
#define MOZ_WM_CHAR (WM_APP+0x031C)
#define MOZ_WM_SYSCHAR (WM_APP+0x031D)
#define MOZ_WM_DEADCHAR (WM_APP+0x031E)
#define MOZ_WM_SYSDEADCHAR (WM_APP+0x031F)
// Internal message for ensuring the file picker is visible on multi monitor
// systems, and when the screen resolution changes.
#define MOZ_WM_ENSUREVISIBLE (WM_APP+0x374F)
// XXX Should rename them to MOZ_WM_* and use safer values!
// Messages for fullscreen transition window
#define WM_FULLSCREEN_TRANSITION_BEFORE (WM_USER + 0)
#define WM_FULLSCREEN_TRANSITION_AFTER (WM_USER + 1)
/*****************************************************************************
* WM_* messages and related constants which may not be defined by
* old Windows SDK
****************************************************************************/
#ifndef SM_CXPADDEDBORDER
#define SM_CXPADDEDBORDER 92
#endif
// require WINVER >= 0x601
#ifndef SM_MAXIMUMTOUCHES
#define SM_MAXIMUMTOUCHES 95
#endif
#ifndef WM_THEMECHANGED
#define WM_THEMECHANGED 0x031A
#endif
#ifndef WM_GETOBJECT
#define WM_GETOBJECT 0x03d
#endif
#ifndef PBT_APMRESUMEAUTOMATIC
#define PBT_APMRESUMEAUTOMATIC 0x0012
#endif
#ifndef WM_MOUSEHWHEEL
#define WM_MOUSEHWHEEL 0x020E
#endif
#ifndef MOUSEEVENTF_HWHEEL
#define MOUSEEVENTF_HWHEEL 0x01000
#endif
#ifndef WM_MOUSELEAVE
#define WM_MOUSELEAVE 0x02A3
#endif
#ifndef SPI_GETWHEELSCROLLCHARS
#define SPI_GETWHEELSCROLLCHARS 0x006C
#endif
#ifndef SPI_SETWHEELSCROLLCHARS
#define SPI_SETWHEELSCROLLCHARS 0x006D
#endif
#ifndef MAPVK_VSC_TO_VK
#define MAPVK_VK_TO_VSC 0
#define MAPVK_VSC_TO_VK 1
#define MAPVK_VK_TO_CHAR 2
#define MAPVK_VSC_TO_VK_EX 3
#define MAPVK_VK_TO_VSC_EX 4
#endif
#ifndef WM_DWMCOMPOSITIONCHANGED
#define WM_DWMCOMPOSITIONCHANGED 0x031E
#endif
#ifndef WM_DWMNCRENDERINGCHANGED
#define WM_DWMNCRENDERINGCHANGED 0x031F
#endif
#ifndef WM_DWMCOLORIZATIONCOLORCHANGED
#define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320
#endif
#ifndef WM_DWMWINDOWMAXIMIZEDCHANGE
#define WM_DWMWINDOWMAXIMIZEDCHANGE 0x0321
#endif
// Drop shadow window style
#define CS_XP_DROPSHADOW 0x00020000
// App Command messages for IntelliMouse and Natural Keyboard Pro
// These messages are not included in Visual C++ 6.0, but are in 7.0+
#ifndef WM_APPCOMMAND
#define WM_APPCOMMAND 0x0319
#endif
#define FAPPCOMMAND_MASK 0xF000
#ifndef WM_GETTITLEBARINFOEX
#define WM_GETTITLEBARINFOEX 0x033F
#endif
#ifndef CCHILDREN_TITLEBAR
#define CCHILDREN_TITLEBAR 5
#endif
#ifndef APPCOMMAND_BROWSER_BACKWARD
#define APPCOMMAND_BROWSER_BACKWARD 1
#define APPCOMMAND_BROWSER_FORWARD 2
#define APPCOMMAND_BROWSER_REFRESH 3
#define APPCOMMAND_BROWSER_STOP 4
#define APPCOMMAND_BROWSER_SEARCH 5
#define APPCOMMAND_BROWSER_FAVORITES 6
#define APPCOMMAND_BROWSER_HOME 7
#define APPCOMMAND_MEDIA_NEXTTRACK 11
#define APPCOMMAND_MEDIA_PREVIOUSTRACK 12
#define APPCOMMAND_MEDIA_STOP 13
#define APPCOMMAND_MEDIA_PLAY_PAUSE 14
/*
* Additional commands currently not in use.
*
*#define APPCOMMAND_VOLUME_MUTE 8
*#define APPCOMMAND_VOLUME_DOWN 9
*#define APPCOMMAND_VOLUME_UP 10
*#define APPCOMMAND_LAUNCH_MAIL 15
*#define APPCOMMAND_LAUNCH_MEDIA_SELECT 16
*#define APPCOMMAND_LAUNCH_APP1 17
*#define APPCOMMAND_LAUNCH_APP2 18
*#define APPCOMMAND_BASS_DOWN 19
*#define APPCOMMAND_BASS_BOOST 20
*#define APPCOMMAND_BASS_UP 21
*#define APPCOMMAND_TREBLE_DOWN 22
*#define APPCOMMAND_TREBLE_UP 23
*#define FAPPCOMMAND_MOUSE 0x8000
*#define FAPPCOMMAND_KEY 0
*#define FAPPCOMMAND_OEM 0x1000
*/
#define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK))
/*
*#define GET_DEVICE_LPARAM(lParam) ((WORD)(HIWORD(lParam) & FAPPCOMMAND_MASK))
*#define GET_MOUSEORKEY_LPARAM GET_DEVICE_LPARAM
*#define GET_FLAGS_LPARAM(lParam) (LOWORD(lParam))
*#define GET_KEYSTATE_LPARAM(lParam) GET_FLAGS_LPARAM(lParam)
*/
#endif // #ifndef APPCOMMAND_BROWSER_BACKWARD
#endif // #ifndef mozilla_widget_WinMessages_h_

View file

@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_widget_WinModifierKeyState_h_
#define mozilla_widget_WinModifierKeyState_h_
#include "mozilla/RefPtr.h"
#include "mozilla/EventForwards.h"
#include <windows.h>
class nsCString;
namespace mozilla {
namespace widget {
class MOZ_STACK_CLASS ModifierKeyState final
{
public:
ModifierKeyState();
ModifierKeyState(bool aIsShiftDown, bool aIsControlDown, bool aIsAltDown);
ModifierKeyState(Modifiers aModifiers);
void Update();
void Unset(Modifiers aRemovingModifiers);
void Set(Modifiers aAddingModifiers);
void InitInputEvent(WidgetInputEvent& aInputEvent) const;
bool IsShift() const;
bool IsControl() const;
bool IsAlt() const;
bool IsAltGr() const;
bool IsWin() const;
bool MaybeMatchShortcutKey() const;
bool IsCapsLocked() const;
bool IsNumLocked() const;
bool IsScrollLocked() const;
MOZ_ALWAYS_INLINE Modifiers GetModifiers() const
{
return mModifiers;
}
private:
Modifiers mModifiers;
MOZ_ALWAYS_INLINE void EnsureAltGr();
void InitMouseEvent(WidgetInputEvent& aMouseEvent) const;
};
const nsCString ToString(const ModifierKeyState& aModifierKeyState);
} // namespace widget
} // namespace mozilla
#endif // #ifndef mozilla_widget_WinModifierKeyState_h_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,625 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_widget_WinMouseScrollHandler_h__
#define mozilla_widget_WinMouseScrollHandler_h__
#include "nscore.h"
#include "nsDebug.h"
#include "mozilla/Assertions.h"
#include "mozilla/EventForwards.h"
#include "mozilla/TimeStamp.h"
#include "Units.h"
#include <windows.h>
#include "nsPoint.h"
class nsWindowBase;
namespace mozilla {
namespace widget {
class ModifierKeyState;
struct MSGResult;
class MouseScrollHandler {
public:
static MouseScrollHandler* GetInstance();
static void Initialize();
static void Shutdown();
static bool NeedsMessage(UINT aMsg);
static bool ProcessMessage(nsWindowBase* aWidget,
UINT msg,
WPARAM wParam,
LPARAM lParam,
MSGResult& aResult);
/**
* See nsIWidget::SynthesizeNativeMouseScrollEvent() for the detail about
* this method.
*/
static nsresult SynthesizeNativeMouseScrollEvent(nsWindowBase* aWidget,
const LayoutDeviceIntPoint& aPoint,
uint32_t aNativeMessage,
int32_t aDelta,
uint32_t aModifierFlags,
uint32_t aAdditionalFlags);
/**
* IsWaitingInternalMessage() returns true if MouseScrollHandler posted
* an internal message for a native mouse wheel message and has not
* received it. Otherwise, false.
*/
static bool IsWaitingInternalMessage()
{
return sInstance && sInstance->mIsWaitingInternalMessage;
}
private:
MouseScrollHandler();
~MouseScrollHandler();
bool mIsWaitingInternalMessage;
static void MaybeLogKeyState();
static MouseScrollHandler* sInstance;
/**
* InitEvent() initializes the aEvent. If aPoint is null, the result of
* GetCurrentMessagePos() will be used.
*/
static void InitEvent(nsWindowBase* aWidget,
WidgetGUIEvent& aEvent,
LayoutDeviceIntPoint* aPoint = nullptr);
/**
* GetModifierKeyState() returns current modifier key state.
* Note that some devices need some hack for the modifier key state.
* This method does it automatically.
*
* @param aMessage Handling message.
*/
static ModifierKeyState GetModifierKeyState(UINT aMessage);
/**
* MozGetMessagePos() returns the mouse cursor position when GetMessage()
* was called last time. However, if we're sending a native message,
* this returns the specified cursor position by
* SynthesizeNativeMouseScrollEvent().
*/
static POINTS GetCurrentMessagePos();
/**
* ProcessNativeMouseWheelMessage() processes WM_MOUSEWHEEL and
* WM_MOUSEHWHEEL. Additionally, processes WM_VSCROLL and WM_HSCROLL if they
* should be processed as mouse wheel message.
* This method posts MOZ_WM_MOUSEVWHEEL, MOZ_WM_MOUSEHWHEEL,
* MOZ_WM_VSCROLL or MOZ_WM_HSCROLL if we need to dispatch mouse scroll
* events. That avoids deadlock with plugin process.
*
* @param aWidget A window which receives the message.
* @param aMessage WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_VSCROLL or
* WM_HSCROLL.
* @param aWParam The wParam value of the message.
* @param aLParam The lParam value of the message.
*/
void ProcessNativeMouseWheelMessage(nsWindowBase* aWidget,
UINT aMessage,
WPARAM aWParam,
LPARAM aLParam);
/**
* ProcessNativeScrollMessage() processes WM_VSCROLL and WM_HSCROLL.
* This method just call ProcessMouseWheelMessage() if the message should be
* processed as mouse wheel message. Otherwise, dispatches a content
* command event.
*
* @param aWidget A window which receives the message.
* @param aMessage WM_VSCROLL or WM_HSCROLL.
* @param aWParam The wParam value of the message.
* @param aLParam The lParam value of the message.
* @return TRUE if the message is processed. Otherwise, FALSE.
*/
bool ProcessNativeScrollMessage(nsWindowBase* aWidget,
UINT aMessage,
WPARAM aWParam,
LPARAM aLParam);
/**
* HandleMouseWheelMessage() processes MOZ_WM_MOUSEVWHEEL and
* MOZ_WM_MOUSEHWHEEL which are posted when one of our windows received
* WM_MOUSEWHEEL or WM_MOUSEHWHEEL for avoiding deadlock with OOPP.
*
* @param aWidget A window which receives the wheel message.
* @param aMessage MOZ_WM_MOUSEWHEEL or MOZ_WM_MOUSEHWHEEL.
* @param aWParam The wParam value of the original message.
* @param aLParam The lParam value of the original message.
*/
void HandleMouseWheelMessage(nsWindowBase* aWidget,
UINT aMessage,
WPARAM aWParam,
LPARAM aLParam);
/**
* HandleScrollMessageAsMouseWheelMessage() processes the MOZ_WM_VSCROLL and
* MOZ_WM_HSCROLL which are posted when one of mouse windows received
* WM_VSCROLL or WM_HSCROLL and user wants them to emulate mouse wheel
* message's behavior.
*
* @param aWidget A window which receives the scroll message.
* @param aMessage MOZ_WM_VSCROLL or MOZ_WM_HSCROLL.
* @param aWParam The wParam value of the original message.
* @param aLParam The lParam value of the original message.
*/
void HandleScrollMessageAsMouseWheelMessage(nsWindowBase* aWidget,
UINT aMessage,
WPARAM aWParam,
LPARAM aLParam);
/**
* ComputeMessagePos() computes the cursor position when the message was
* added to the queue.
*
* @param aMessage Handling message.
* @param aWParam Handling message's wParam.
* @param aLParam Handling message's lParam.
* @return Mouse cursor position when the message is added to
* the queue or current cursor position if the result of
* ::GetMessagePos() is broken.
*/
POINT ComputeMessagePos(UINT aMessage,
WPARAM aWParam,
LPARAM aLParam);
class EventInfo {
public:
/**
* @param aWidget An nsWindow which is handling the event.
* @param aMessage Must be WM_MOUSEWHEEL or WM_MOUSEHWHEEL.
*/
EventInfo(nsWindowBase* aWidget, UINT aMessage, WPARAM aWParam, LPARAM aLParam);
bool CanDispatchWheelEvent() const;
int32_t GetNativeDelta() const { return mDelta; }
HWND GetWindowHandle() const { return mWnd; }
const TimeStamp& GetTimeStamp() const { return mTimeStamp; }
bool IsVertical() const { return mIsVertical; }
bool IsPositive() const { return (mDelta > 0); }
bool IsPage() const { return mIsPage; }
/**
* @return Number of lines or pages scrolled per WHEEL_DELTA.
*/
int32_t GetScrollAmount() const;
protected:
EventInfo() :
mIsVertical(false), mIsPage(false), mDelta(0), mWnd(nullptr)
{
}
// TRUE if event is for vertical scroll. Otherwise, FALSE.
bool mIsVertical;
// TRUE if event scrolls per page, otherwise, FALSE.
bool mIsPage;
// The native delta value.
int32_t mDelta;
// The window handle which is handling the event.
HWND mWnd;
// Timestamp of the event.
TimeStamp mTimeStamp;
};
class LastEventInfo : public EventInfo {
public:
LastEventInfo() :
EventInfo(), mAccumulatedDelta(0)
{
}
/**
* CanContinueTransaction() checks whether the new event can continue the
* last transaction or not. Note that if there is no transaction, this
* returns true.
*/
bool CanContinueTransaction(const EventInfo& aNewEvent);
/**
* ResetTransaction() resets the transaction, i.e., the instance forgets
* the last event information.
*/
void ResetTransaction();
/**
* RecordEvent() saves the information of new event.
*/
void RecordEvent(const EventInfo& aEvent);
/**
* InitWheelEvent() initializes NS_WHEEL_WHEEL event and
* recomputes the remaning detla for the event.
* This must be called only once during handling a message and after
* RecordEvent() is called.
*
* @param aWidget A window which will dispatch the event.
* @param aWheelEvent An NS_WHEEL_WHEEL event, this will be
* initialized.
* @param aModKeyState Current modifier key state.
* @return TRUE if the event is ready to dispatch.
* Otherwise, FALSE.
*/
bool InitWheelEvent(nsWindowBase* aWidget,
WidgetWheelEvent& aWheelEvent,
const ModifierKeyState& aModKeyState);
private:
static int32_t RoundDelta(double aDelta);
int32_t mAccumulatedDelta;
};
LastEventInfo mLastEventInfo;
class SystemSettings {
public:
SystemSettings() : mInitialized(false) {}
void Init();
void MarkDirty();
void NotifyUserPrefsMayOverrideSystemSettings();
// On some environments, SystemParametersInfo() may be hooked by touchpad
// utility or something. In such case, when user changes active pointing
// device to another one, the result of SystemParametersInfo() may be
// changed without WM_SETTINGCHANGE message. For avoiding this trouble,
// we need to modify cache of system settings at every wheel message
// handling if we meet known device whose utility may hook the API.
void TrustedScrollSettingsDriver();
// Returns true if the system scroll may be overridden for faster scroll.
// Otherwise, false. For example, if the user maybe uses an expensive
// mouse which supports acceleration of scroll speed, faster scroll makes
// the user inconvenient.
bool IsOverridingSystemScrollSpeedAllowed();
int32_t GetScrollAmount(bool aForVertical) const
{
MOZ_ASSERT(mInitialized, "SystemSettings must be initialized");
return aForVertical ? mScrollLines : mScrollChars;
}
bool IsPageScroll(bool aForVertical) const
{
MOZ_ASSERT(mInitialized, "SystemSettings must be initialized");
return aForVertical ? (uint32_t(mScrollLines) == WHEEL_PAGESCROLL) :
(uint32_t(mScrollChars) == WHEEL_PAGESCROLL);
}
// The default vertical and horizontal scrolling speed is 3, this is defined
// on the document of SystemParametersInfo in MSDN.
static int32_t DefaultScrollLines() { return 3; }
static int32_t DefaultScrollChars() { return 3; }
private:
bool mInitialized;
// The result of SystemParametersInfo() may not be reliable since it may
// be hooked. So, if the values are initialized with prefs, we can trust
// the value. Following mIsReliableScroll* are set true when mScroll* are
// initialized with prefs.
bool mIsReliableScrollLines;
bool mIsReliableScrollChars;
int32_t mScrollLines;
int32_t mScrollChars;
// Returns true if cached value is changed.
bool InitScrollLines();
bool InitScrollChars();
void RefreshCache();
};
SystemSettings mSystemSettings;
class UserPrefs {
public:
UserPrefs();
~UserPrefs();
void MarkDirty();
bool IsScrollMessageHandledAsWheelMessage()
{
Init();
return mScrollMessageHandledAsWheelMessage;
}
bool IsSystemSettingCacheEnabled()
{
Init();
return mEnableSystemSettingCache;
}
bool IsSystemSettingCacheForciblyEnabled()
{
Init();
return mForceEnableSystemSettingCache;
}
int32_t GetOverriddenVerticalScrollAmout()
{
Init();
return mOverriddenVerticalScrollAmount;
}
int32_t GetOverriddenHorizontalScrollAmout()
{
Init();
return mOverriddenHorizontalScrollAmount;
}
int32_t GetMouseScrollTransactionTimeout()
{
Init();
return mMouseScrollTransactionTimeout;
}
private:
void Init();
static void OnChange(const char* aPrefName, void* aClosure)
{
static_cast<UserPrefs*>(aClosure)->MarkDirty();
}
bool mInitialized;
bool mScrollMessageHandledAsWheelMessage;
bool mEnableSystemSettingCache;
bool mForceEnableSystemSettingCache;
int32_t mOverriddenVerticalScrollAmount;
int32_t mOverriddenHorizontalScrollAmount;
int32_t mMouseScrollTransactionTimeout;
};
UserPrefs mUserPrefs;
class SynthesizingEvent {
public:
SynthesizingEvent() :
mWnd(nullptr), mMessage(0), mWParam(0), mLParam(0),
mStatus(NOT_SYNTHESIZING)
{
}
~SynthesizingEvent() {}
static bool IsSynthesizing();
nsresult Synthesize(const POINTS& aCursorPoint, HWND aWnd,
UINT aMessage, WPARAM aWParam, LPARAM aLParam,
const BYTE (&aKeyStates)[256]);
void NativeMessageReceived(nsWindowBase* aWidget, UINT aMessage,
WPARAM aWParam, LPARAM aLParam);
void NotifyNativeMessageHandlingFinished();
void NotifyInternalMessageHandlingFinished();
const POINTS& GetCursorPoint() const { return mCursorPoint; }
private:
POINTS mCursorPoint;
HWND mWnd;
UINT mMessage;
WPARAM mWParam;
LPARAM mLParam;
BYTE mKeyState[256];
BYTE mOriginalKeyState[256];
enum Status {
NOT_SYNTHESIZING,
SENDING_MESSAGE,
NATIVE_MESSAGE_RECEIVED,
INTERNAL_MESSAGE_POSTED,
};
Status mStatus;
const char* GetStatusName()
{
switch (mStatus) {
case NOT_SYNTHESIZING:
return "NOT_SYNTHESIZING";
case SENDING_MESSAGE:
return "SENDING_MESSAGE";
case NATIVE_MESSAGE_RECEIVED:
return "NATIVE_MESSAGE_RECEIVED";
case INTERNAL_MESSAGE_POSTED:
return "INTERNAL_MESSAGE_POSTED";
default:
return "Unknown";
}
}
void Finish();
}; // SynthesizingEvent
SynthesizingEvent* mSynthesizingEvent;
public:
class Device {
public:
// SynTP is a touchpad driver of Synaptics.
class SynTP
{
public:
static bool IsDriverInstalled()
{
return sMajorVersion != 0;
}
/**
* GetDriverMajorVersion() returns the installed driver's major version.
* If SynTP driver isn't installed, this returns 0.
*/
static int32_t GetDriverMajorVersion()
{
return sMajorVersion;
}
/**
* GetDriverMinorVersion() returns the installed driver's minor version.
* If SynTP driver isn't installed, this returns -1.
*/
static int32_t GetDriverMinorVersion()
{
return sMinorVersion;
}
static void Init();
private:
static bool sInitialized;
static int32_t sMajorVersion;
static int32_t sMinorVersion;
};
class Elantech {
public:
/**
* GetDriverMajorVersion() returns the installed driver's major version.
* If Elantech's driver was installed, returns 0.
*/
static int32_t GetDriverMajorVersion();
/**
* IsHelperWindow() checks whether aWnd is a helper window of Elantech's
* touchpad. Returns TRUE if so. Otherwise, FALSE.
*/
static bool IsHelperWindow(HWND aWnd);
/**
* Key message handler for Elantech's hack. Returns TRUE if the message
* is consumed by this handler. Otherwise, FALSE.
*/
static bool HandleKeyMessage(nsWindowBase* aWidget,
UINT aMsg,
WPARAM aWParam,
LPARAM aLParam);
static void UpdateZoomUntil();
static bool IsZooming();
static void Init();
static bool IsPinchHackNeeded() { return sUsePinchHack; }
private:
// Whether to enable the Elantech swipe gesture hack.
static bool sUseSwipeHack;
// Whether to enable the Elantech pinch-to-zoom gesture hack.
static bool sUsePinchHack;
static DWORD sZoomUntil;
}; // class Elantech
// Apoint is a touchpad driver of Alps.
class Apoint
{
public:
static bool IsDriverInstalled()
{
return sMajorVersion != 0;
}
/**
* GetDriverMajorVersion() returns the installed driver's major version.
* If Apoint driver isn't installed, this returns 0.
*/
static int32_t GetDriverMajorVersion()
{
return sMajorVersion;
}
/**
* GetDriverMinorVersion() returns the installed driver's minor version.
* If Apoint driver isn't installed, this returns -1.
*/
static int32_t GetDriverMinorVersion()
{
return sMinorVersion;
}
static void Init();
private:
static bool sInitialized;
static int32_t sMajorVersion;
static int32_t sMinorVersion;
};
class TrackPoint {
public:
/**
* IsDriverInstalled() returns TRUE if TrackPoint's driver is installed.
* Otherwise, returns FALSE.
*/
static bool IsDriverInstalled();
}; // class TrackPoint
class UltraNav {
public:
/**
* IsObsoleteDriverInstalled() checks whether obsoleted UltraNav
* is installed on the environment.
* Returns TRUE if it was installed. Otherwise, FALSE.
*/
static bool IsObsoleteDriverInstalled();
}; // class UltraNav
class SetPoint {
public:
/**
* SetPoint, Logitech's mouse driver, may report wrong cursor position
* for WM_MOUSEHWHEEL message. See comment in the implementation for
* the detail.
*/
static bool IsGetMessagePosResponseValid(UINT aMessage,
WPARAM aWParam,
LPARAM aLParam);
private:
static bool sMightBeUsing;
};
static void Init();
static bool IsFakeScrollableWindowNeeded()
{
return sFakeScrollableWindowNeeded;
}
private:
/**
* Gets the bool value of aPrefName used to enable or disable an input
* workaround (like the Trackpoint hack). The pref can take values 0 (for
* disabled), 1 (for enabled) or -1 (to automatically detect whether to
* enable the workaround).
*
* @param aPrefName The name of the pref.
* @param aValueIfAutomatic Whether the given input workaround should be
* enabled by default.
*/
static bool GetWorkaroundPref(const char* aPrefName,
bool aValueIfAutomatic);
static bool sFakeScrollableWindowNeeded;
}; // class Device
};
} // namespace widget
} // namespace mozilla
#endif // mozilla_widget_WinMouseScrollHandler_h__

View file

@ -0,0 +1,56 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_widget_WinNativeEventData_h_
#define mozilla_widget_WinNativeEventData_h_
#include <windows.h>
#include "mozilla/EventForwards.h"
#include "mozilla/widget/WinModifierKeyState.h"
namespace mozilla {
namespace widget {
/**
* WinNativeKeyEventData is used by nsIWidget::OnWindowedPluginKeyEvent() and
* related IPC methods. This class cannot hold any pointers and references
* since which are not available in different process.
*/
class WinNativeKeyEventData final
{
public:
UINT mMessage;
WPARAM mWParam;
LPARAM mLParam;
Modifiers mModifiers;
private:
uintptr_t mKeyboardLayout;
public:
WinNativeKeyEventData(UINT aMessage,
WPARAM aWParam,
LPARAM aLParam,
const ModifierKeyState& aModifierKeyState)
: mMessage(aMessage)
, mWParam(aWParam)
, mLParam(aLParam)
, mModifiers(aModifierKeyState.GetModifiers())
, mKeyboardLayout(reinterpret_cast<uintptr_t>(::GetKeyboardLayout(0)))
{
}
HKL GetKeyboardLayout() const
{
return reinterpret_cast<HKL>(mKeyboardLayout);
}
};
} // namespace widget
} // namespace mozilla
#endif // #ifndef mozilla_widget_WinNativeEventData_h_

View file

@ -0,0 +1,506 @@
/* vim: se cin sw=2 ts=2 et : */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WinTaskbar.h"
#include "TaskbarPreview.h"
#include <nsITaskbarPreviewController.h>
#include "mozilla/RefPtr.h"
#include <nsError.h>
#include <nsCOMPtr.h>
#include <nsIWidget.h>
#include <nsIBaseWindow.h>
#include <nsIObserverService.h>
#include <nsServiceManagerUtils.h>
#include "nsIXULAppInfo.h"
#include "nsIJumpListBuilder.h"
#include "nsUXThemeData.h"
#include "nsWindow.h"
#include "WinUtils.h"
#include "TaskbarTabPreview.h"
#include "TaskbarWindowPreview.h"
#include "JumpListBuilder.h"
#include "nsWidgetsCID.h"
#include "nsPIDOMWindow.h"
#include "nsAppDirectoryServiceDefs.h"
#include "mozilla/Preferences.h"
#include "mozilla/WindowsVersion.h"
#include <io.h>
#include <propvarutil.h>
#include <propkey.h>
#include <shellapi.h>
const wchar_t kShellLibraryName[] = L"shell32.dll";
static NS_DEFINE_CID(kJumpListBuilderCID, NS_WIN_JUMPLISTBUILDER_CID);
namespace {
HWND
GetHWNDFromDocShell(nsIDocShell *aShell) {
nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(reinterpret_cast<nsISupports*>(aShell)));
if (!baseWindow)
return nullptr;
nsCOMPtr<nsIWidget> widget;
baseWindow->GetMainWidget(getter_AddRefs(widget));
return widget ? (HWND)widget->GetNativeData(NS_NATIVE_WINDOW) : nullptr;
}
HWND
GetHWNDFromDOMWindow(mozIDOMWindow *dw) {
nsCOMPtr<nsIWidget> widget;
if (!dw)
return nullptr;
nsCOMPtr<nsPIDOMWindowInner> window = nsPIDOMWindowInner::From(dw);
return GetHWNDFromDocShell(window->GetDocShell());
}
nsresult
SetWindowAppUserModelProp(mozIDOMWindow *aParent,
const nsString & aIdentifier) {
NS_ENSURE_ARG_POINTER(aParent);
if (aIdentifier.IsEmpty())
return NS_ERROR_INVALID_ARG;
HWND toplevelHWND = ::GetAncestor(GetHWNDFromDOMWindow(aParent), GA_ROOT);
if (!toplevelHWND)
return NS_ERROR_INVALID_ARG;
typedef HRESULT (WINAPI * SHGetPropertyStoreForWindowPtr)
(HWND hwnd, REFIID riid, void** ppv);
SHGetPropertyStoreForWindowPtr funcGetProStore = nullptr;
HMODULE hDLL = ::LoadLibraryW(kShellLibraryName);
funcGetProStore = (SHGetPropertyStoreForWindowPtr)
GetProcAddress(hDLL, "SHGetPropertyStoreForWindow");
if (!funcGetProStore) {
FreeLibrary(hDLL);
return NS_ERROR_NO_INTERFACE;
}
IPropertyStore* pPropStore;
if (FAILED(funcGetProStore(toplevelHWND,
IID_PPV_ARGS(&pPropStore)))) {
FreeLibrary(hDLL);
return NS_ERROR_INVALID_ARG;
}
PROPVARIANT pv;
if (FAILED(InitPropVariantFromString(aIdentifier.get(), &pv))) {
pPropStore->Release();
FreeLibrary(hDLL);
return NS_ERROR_UNEXPECTED;
}
nsresult rv = NS_OK;
if (FAILED(pPropStore->SetValue(PKEY_AppUserModel_ID, pv)) ||
FAILED(pPropStore->Commit())) {
rv = NS_ERROR_FAILURE;
}
PropVariantClear(&pv);
pPropStore->Release();
FreeLibrary(hDLL);
return rv;
}
///////////////////////////////////////////////////////////////////////////////
// default nsITaskbarPreviewController
class DefaultController final : public nsITaskbarPreviewController
{
~DefaultController() {}
HWND mWnd;
public:
DefaultController(HWND hWnd)
: mWnd(hWnd)
{
}
NS_DECL_ISUPPORTS
NS_DECL_NSITASKBARPREVIEWCONTROLLER
};
NS_IMETHODIMP
DefaultController::GetWidth(uint32_t *aWidth)
{
RECT r;
::GetClientRect(mWnd, &r);
*aWidth = r.right;
return NS_OK;
}
NS_IMETHODIMP
DefaultController::GetHeight(uint32_t *aHeight)
{
RECT r;
::GetClientRect(mWnd, &r);
*aHeight = r.bottom;
return NS_OK;
}
NS_IMETHODIMP
DefaultController::GetThumbnailAspectRatio(float *aThumbnailAspectRatio) {
uint32_t width, height;
GetWidth(&width);
GetHeight(&height);
if (!height)
height = 1;
*aThumbnailAspectRatio = width/float(height);
return NS_OK;
}
// deprecated
NS_IMETHODIMP
DefaultController::DrawPreview(nsISupports *ctx, bool *rDrawFrame) {
*rDrawFrame = true;
return NS_ERROR_UNEXPECTED;
}
// deprecated
NS_IMETHODIMP
DefaultController::DrawThumbnail(nsISupports *ctx, uint32_t width, uint32_t height, bool *rDrawFrame) {
*rDrawFrame = false;
return NS_ERROR_UNEXPECTED;
}
NS_IMETHODIMP
DefaultController::RequestThumbnail(nsITaskbarPreviewCallback *aCallback, uint32_t width, uint32_t height) {
return NS_OK;
}
NS_IMETHODIMP
DefaultController::RequestPreview(nsITaskbarPreviewCallback *aCallback) {
return NS_OK;
}
NS_IMETHODIMP
DefaultController::OnClose(void) {
NS_NOTREACHED("OnClose should not be called for TaskbarWindowPreviews");
return NS_OK;
}
NS_IMETHODIMP
DefaultController::OnActivate(bool *rAcceptActivation) {
*rAcceptActivation = true;
NS_NOTREACHED("OnActivate should not be called for TaskbarWindowPreviews");
return NS_OK;
}
NS_IMETHODIMP
DefaultController::OnClick(nsITaskbarPreviewButton *button) {
return NS_OK;
}
NS_IMPL_ISUPPORTS(DefaultController, nsITaskbarPreviewController)
}
namespace mozilla {
namespace widget {
///////////////////////////////////////////////////////////////////////////////
// nsIWinTaskbar
NS_IMPL_ISUPPORTS(WinTaskbar, nsIWinTaskbar)
bool
WinTaskbar::Initialize() {
if (mTaskbar)
return true;
::CoInitialize(nullptr);
HRESULT hr = ::CoCreateInstance(CLSID_TaskbarList,
nullptr,
CLSCTX_INPROC_SERVER,
IID_ITaskbarList4,
(void**)&mTaskbar);
if (FAILED(hr))
return false;
hr = mTaskbar->HrInit();
if (FAILED(hr)) {
// This may fail with shell extensions like blackbox installed.
NS_WARNING("Unable to initialize taskbar");
NS_RELEASE(mTaskbar);
return false;
}
return true;
}
WinTaskbar::WinTaskbar()
: mTaskbar(nullptr) {
}
WinTaskbar::~WinTaskbar() {
if (mTaskbar) { // match successful Initialize() call
NS_RELEASE(mTaskbar);
::CoUninitialize();
}
}
// static
bool
WinTaskbar::GetAppUserModelID(nsAString & aDefaultGroupId) {
// If marked as such in prefs, use a hash of the profile path for the id
// instead of the install path hash setup by the installer.
bool useProfile =
Preferences::GetBool("taskbar.grouping.useprofile", false);
if (useProfile) {
nsCOMPtr<nsIFile> profileDir;
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(profileDir));
bool exists = false;
if (profileDir && NS_SUCCEEDED(profileDir->Exists(&exists)) && exists) {
nsAutoCString path;
if (NS_SUCCEEDED(profileDir->GetNativePath(path))) {
nsAutoString id;
id.AppendInt(HashString(path));
if (!id.IsEmpty()) {
aDefaultGroupId.Assign(id);
return true;
}
}
}
}
// The default value is set by the installer and is stored in the registry
// under (HKLM||HKCU)/Software/Mozilla/Firefox/TaskBarIDs. If for any reason
// hash generation operation fails, the installer will not store a value in
// the registry or set ids on shortcuts. A lack of an id can also occur for
// zipped builds. We skip setting the global id in this case as well.
nsCOMPtr<nsIXULAppInfo> appInfo =
do_GetService("@mozilla.org/xre/app-info;1");
if (!appInfo)
return false;
nsCString appName;
if (NS_FAILED(appInfo->GetName(appName))) {
// We just won't register then, let Windows handle it.
return false;
}
nsAutoString regKey;
regKey.AssignLiteral("Software\\Mozilla\\");
AppendASCIItoUTF16(appName, regKey);
regKey.AppendLiteral("\\TaskBarIDs");
WCHAR path[MAX_PATH];
if (GetModuleFileNameW(nullptr, path, MAX_PATH)) {
wchar_t* slash = wcsrchr(path, '\\');
if (!slash)
return false;
*slash = '\0'; // no trailing slash
// The hash is short, but users may customize this, so use a respectable
// string buffer.
wchar_t buf[256];
if (WinUtils::GetRegistryKey(HKEY_LOCAL_MACHINE,
regKey.get(),
path,
buf,
sizeof buf)) {
aDefaultGroupId.Assign(buf);
} else if (WinUtils::GetRegistryKey(HKEY_CURRENT_USER,
regKey.get(),
path,
buf,
sizeof buf)) {
aDefaultGroupId.Assign(buf);
}
}
return !aDefaultGroupId.IsEmpty();
return true;
}
NS_IMETHODIMP
WinTaskbar::GetDefaultGroupId(nsAString & aDefaultGroupId) {
if (!GetAppUserModelID(aDefaultGroupId))
return NS_ERROR_UNEXPECTED;
return NS_OK;
}
// (static) Called from AppShell
bool
WinTaskbar::RegisterAppUserModelID() {
if (!IsWin7OrLater())
return false;
SetCurrentProcessExplicitAppUserModelIDPtr funcAppUserModelID = nullptr;
bool retVal = false;
nsAutoString uid;
if (!GetAppUserModelID(uid))
return false;
HMODULE hDLL = ::LoadLibraryW(kShellLibraryName);
funcAppUserModelID = (SetCurrentProcessExplicitAppUserModelIDPtr)
GetProcAddress(hDLL, "SetCurrentProcessExplicitAppUserModelID");
if (!funcAppUserModelID) {
::FreeLibrary(hDLL);
return false;
}
if (SUCCEEDED(funcAppUserModelID(uid.get())))
retVal = true;
if (hDLL)
::FreeLibrary(hDLL);
return retVal;
}
NS_IMETHODIMP
WinTaskbar::GetAvailable(bool *aAvailable) {
// ITaskbarList4::HrInit() may fail with shell extensions like blackbox
// installed. Initialize early to return available=false in those cases.
*aAvailable = IsWin7OrLater() && Initialize();
return NS_OK;
}
NS_IMETHODIMP
WinTaskbar::CreateTaskbarTabPreview(nsIDocShell *shell, nsITaskbarPreviewController *controller, nsITaskbarTabPreview **_retval) {
if (!Initialize())
return NS_ERROR_NOT_AVAILABLE;
NS_ENSURE_ARG_POINTER(shell);
NS_ENSURE_ARG_POINTER(controller);
HWND toplevelHWND = ::GetAncestor(GetHWNDFromDocShell(shell), GA_ROOT);
if (!toplevelHWND)
return NS_ERROR_INVALID_ARG;
RefPtr<TaskbarTabPreview> preview(new TaskbarTabPreview(mTaskbar, controller, toplevelHWND, shell));
if (!preview)
return NS_ERROR_OUT_OF_MEMORY;
preview.forget(_retval);
return NS_OK;
}
NS_IMETHODIMP
WinTaskbar::GetTaskbarWindowPreview(nsIDocShell *shell, nsITaskbarWindowPreview **_retval) {
if (!Initialize())
return NS_ERROR_NOT_AVAILABLE;
NS_ENSURE_ARG_POINTER(shell);
HWND toplevelHWND = ::GetAncestor(GetHWNDFromDocShell(shell), GA_ROOT);
if (!toplevelHWND)
return NS_ERROR_INVALID_ARG;
nsWindow *window = WinUtils::GetNSWindowPtr(toplevelHWND);
if (!window)
return NS_ERROR_FAILURE;
nsCOMPtr<nsITaskbarWindowPreview> preview = window->GetTaskbarPreview();
if (!preview) {
RefPtr<DefaultController> defaultController = new DefaultController(toplevelHWND);
preview = new TaskbarWindowPreview(mTaskbar, defaultController, toplevelHWND, shell);
if (!preview)
return NS_ERROR_OUT_OF_MEMORY;
window->SetTaskbarPreview(preview);
}
preview.forget(_retval);
return NS_OK;
}
NS_IMETHODIMP
WinTaskbar::GetTaskbarProgress(nsIDocShell *shell, nsITaskbarProgress **_retval) {
nsCOMPtr<nsITaskbarWindowPreview> preview;
nsresult rv = GetTaskbarWindowPreview(shell, getter_AddRefs(preview));
NS_ENSURE_SUCCESS(rv, rv);
return CallQueryInterface(preview, _retval);
}
NS_IMETHODIMP
WinTaskbar::GetOverlayIconController(nsIDocShell *shell,
nsITaskbarOverlayIconController **_retval) {
nsCOMPtr<nsITaskbarWindowPreview> preview;
nsresult rv = GetTaskbarWindowPreview(shell, getter_AddRefs(preview));
NS_ENSURE_SUCCESS(rv, rv);
return CallQueryInterface(preview, _retval);
}
NS_IMETHODIMP
WinTaskbar::CreateJumpListBuilder(nsIJumpListBuilder * *aJumpListBuilder) {
nsresult rv;
if (JumpListBuilder::sBuildingList)
return NS_ERROR_ALREADY_INITIALIZED;
nsCOMPtr<nsIJumpListBuilder> builder =
do_CreateInstance(kJumpListBuilderCID, &rv);
if (NS_FAILED(rv))
return NS_ERROR_UNEXPECTED;
NS_IF_ADDREF(*aJumpListBuilder = builder);
return NS_OK;
}
NS_IMETHODIMP
WinTaskbar::SetGroupIdForWindow(mozIDOMWindow *aParent,
const nsAString & aIdentifier) {
return SetWindowAppUserModelProp(aParent, nsString(aIdentifier));
}
NS_IMETHODIMP
WinTaskbar::PrepareFullScreen(mozIDOMWindow *aWindow, bool aFullScreen) {
NS_ENSURE_ARG_POINTER(aWindow);
HWND toplevelHWND = ::GetAncestor(GetHWNDFromDOMWindow(aWindow), GA_ROOT);
if (!toplevelHWND)
return NS_ERROR_INVALID_ARG;
return PrepareFullScreenHWND(toplevelHWND, aFullScreen);
}
NS_IMETHODIMP
WinTaskbar::PrepareFullScreenHWND(void *aHWND, bool aFullScreen) {
if (!Initialize())
return NS_ERROR_NOT_AVAILABLE;
NS_ENSURE_ARG_POINTER(aHWND);
if (!::IsWindow((HWND)aHWND))
return NS_ERROR_INVALID_ARG;
HRESULT hr = mTaskbar->MarkFullscreenWindow((HWND)aHWND, aFullScreen);
if (FAILED(hr)) {
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,46 @@
/* vim: se cin sw=2 ts=2 et : */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __WinTaskbar_h__
#define __WinTaskbar_h__
#include <windows.h>
#include <shobjidl.h>
#undef LogSeverity // SetupAPI.h #defines this as DWORD
#include "nsIWinTaskbar.h"
#include "mozilla/Attributes.h"
namespace mozilla {
namespace widget {
class WinTaskbar final : public nsIWinTaskbar
{
~WinTaskbar();
public:
WinTaskbar();
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIWINTASKBAR
// Registers the global app user model id for the instance.
// See comments in WinTaskbar.cpp for more information.
static bool RegisterAppUserModelID();
static bool GetAppUserModelID(nsAString & aDefaultGroupId);
private:
bool Initialize();
typedef HRESULT (WINAPI * SetCurrentProcessExplicitAppUserModelIDPtr)(PCWSTR AppID);
ITaskbarList4 *mTaskbar;
};
} // namespace widget
} // namespace mozilla
#endif /* __WinTaskbar_h__ */

View file

@ -0,0 +1,78 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "KeyboardLayout.h"
#include "mozilla/TextEventDispatcher.h"
#include "mozilla/widget/IMEData.h"
#include "nsWindow.h"
#include "WinIMEHandler.h"
#include "WinTextEventDispatcherListener.h"
namespace mozilla {
namespace widget {
StaticRefPtr<WinTextEventDispatcherListener>
WinTextEventDispatcherListener::sInstance;
// static
WinTextEventDispatcherListener*
WinTextEventDispatcherListener::GetInstance()
{
if (!sInstance) {
sInstance = new WinTextEventDispatcherListener();
}
return sInstance.get();
}
void
WinTextEventDispatcherListener::Shutdown()
{
sInstance = nullptr;
}
NS_IMPL_ISUPPORTS(WinTextEventDispatcherListener,
TextEventDispatcherListener,
nsISupportsWeakReference)
WinTextEventDispatcherListener::WinTextEventDispatcherListener()
{
}
WinTextEventDispatcherListener::~WinTextEventDispatcherListener()
{
}
NS_IMETHODIMP
WinTextEventDispatcherListener::NotifyIME(
TextEventDispatcher* aTextEventDispatcher,
const IMENotification& aNotification)
{
nsWindow* window = static_cast<nsWindow*>(aTextEventDispatcher->GetWidget());
if (NS_WARN_IF(!window)) {
return NS_ERROR_FAILURE;
}
return IMEHandler::NotifyIME(window, aNotification);
}
NS_IMETHODIMP_(void)
WinTextEventDispatcherListener::OnRemovedFrom(
TextEventDispatcher* aTextEventDispatcher)
{
// XXX When input transaction is being stolen by add-on, what should we do?
}
NS_IMETHODIMP_(void)
WinTextEventDispatcherListener::WillDispatchKeyboardEvent(
TextEventDispatcher* aTextEventDispatcher,
WidgetKeyboardEvent& aKeyboardEvent,
uint32_t aIndexOfKeypress,
void* aData)
{
static_cast<NativeKey*>(aData)->
WillDispatchKeyboardEvent(aKeyboardEvent, aIndexOfKeypress);
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,50 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef WinTextEventDispatcherListener_h_
#define WinTextEventDispatcherListener_h_
#include "mozilla/Attributes.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/TextEventDispatcherListener.h"
namespace mozilla {
namespace widget {
/**
* On Windows, it's enough TextEventDispatcherListener to be a singleton
* because we have only one input context per process (IMM can create
* multiple IM context but we don't support such behavior).
*/
class WinTextEventDispatcherListener final : public TextEventDispatcherListener
{
public:
static WinTextEventDispatcherListener* GetInstance();
static void Shutdown();
NS_DECL_ISUPPORTS
NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,
const IMENotification& aNotification) override;
NS_IMETHOD_(void) OnRemovedFrom(
TextEventDispatcher* aTextEventDispatcher) override;
NS_IMETHOD_(void) WillDispatchKeyboardEvent(
TextEventDispatcher* aTextEventDispatcher,
WidgetKeyboardEvent& aKeyboardEvent,
uint32_t aIndexOfKeypress,
void* aData) override;
private:
WinTextEventDispatcherListener();
virtual ~WinTextEventDispatcherListener();
static StaticRefPtr<WinTextEventDispatcherListener> sInstance;
};
} // namespace widget
} // namespace mozilla
#endif // #ifndef WinTextEventDispatcherListener_h_

2110
widget/windows/WinUtils.cpp Normal file

File diff suppressed because it is too large Load diff

648
widget/windows/WinUtils.h Normal file
View file

@ -0,0 +1,648 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_widget_WinUtils_h__
#define mozilla_widget_WinUtils_h__
#include "nscore.h"
#include <windows.h>
#include <shobjidl.h>
#include <uxtheme.h>
#include <dwmapi.h>
// Undo the windows.h damage
#undef GetMessage
#undef CreateEvent
#undef GetClassName
#undef GetBinaryType
#undef RemoveDirectory
#include "nsString.h"
#include "nsRegion.h"
#include "nsRect.h"
#include "nsIRunnable.h"
#include "nsICryptoHash.h"
#ifdef MOZ_PLACES
#include "nsIFaviconService.h"
#endif
#include "nsIDownloader.h"
#include "nsIURI.h"
#include "nsIWidget.h"
#include "nsIThread.h"
#include "mozilla/Attributes.h"
#include "mozilla/EventForwards.h"
#include "mozilla/UniquePtr.h"
/**
* NS_INLINE_DECL_IUNKNOWN_REFCOUNTING should be used for defining and
* implementing AddRef() and Release() of IUnknown interface.
* This depends on xpcom/glue/nsISupportsImpl.h.
*/
#define NS_INLINE_DECL_IUNKNOWN_REFCOUNTING(_class) \
public: \
STDMETHODIMP_(ULONG) AddRef() \
{ \
MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
NS_ASSERT_OWNINGTHREAD(_class); \
++mRefCnt; \
NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this)); \
return static_cast<ULONG>(mRefCnt.get()); \
} \
STDMETHODIMP_(ULONG) Release() \
{ \
MOZ_ASSERT(int32_t(mRefCnt) > 0, \
"Release called on object that has already been released!"); \
NS_ASSERT_OWNINGTHREAD(_class); \
--mRefCnt; \
NS_LOG_RELEASE(this, mRefCnt, #_class); \
if (mRefCnt == 0) { \
NS_ASSERT_OWNINGTHREAD(_class); \
mRefCnt = 1; /* stabilize */ \
delete this; \
return 0; \
} \
return static_cast<ULONG>(mRefCnt.get()); \
} \
protected: \
nsAutoRefCnt mRefCnt; \
NS_DECL_OWNINGTHREAD \
public:
class nsWindow;
class nsWindowBase;
struct KeyPair;
#if !defined(DPI_AWARENESS_CONTEXT_DECLARED) && !defined(DPI_AWARENESS_CONTEXT_UNAWARE)
DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
typedef enum DPI_AWARENESS {
DPI_AWARENESS_INVALID = -1,
DPI_AWARENESS_UNAWARE = 0,
DPI_AWARENESS_SYSTEM_AWARE = 1,
DPI_AWARENESS_PER_MONITOR_AWARE = 2
} DPI_AWARENESS;
#define DPI_AWARENESS_CONTEXT_UNAWARE ((DPI_AWARENESS_CONTEXT)-1)
#define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ((DPI_AWARENESS_CONTEXT)-2)
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ((DPI_AWARENESS_CONTEXT)-3)
#define DPI_AWARENESS_CONTEXT_DECLARED
#endif // (DPI_AWARENESS_CONTEXT_DECLARED)
typedef DPI_AWARENESS_CONTEXT(WINAPI * SetThreadDpiAwarenessContextProc)(DPI_AWARENESS_CONTEXT);
typedef BOOL(WINAPI * EnableNonClientDpiScalingProc)(HWND);
namespace mozilla {
namespace widget {
// Windows message debugging data
typedef struct {
const char * mStr;
UINT mId;
} EventMsgInfo;
extern EventMsgInfo gAllEvents[];
// More complete QS definitions for MsgWaitForMultipleObjects() and
// GetQueueStatus() that include newer win8 specific defines.
#ifndef QS_RAWINPUT
#define QS_RAWINPUT 0x0400
#endif
#ifndef QS_TOUCH
#define QS_TOUCH 0x0800
#define QS_POINTER 0x1000
#endif
#define MOZ_QS_ALLEVENT (QS_KEY | QS_MOUSEMOVE | QS_MOUSEBUTTON | \
QS_POSTMESSAGE | QS_TIMER | QS_PAINT | \
QS_SENDMESSAGE | QS_HOTKEY | \
QS_ALLPOSTMESSAGE | QS_RAWINPUT | \
QS_TOUCH | QS_POINTER)
// Logging macros
#define LogFunction() mozilla::widget::WinUtils::Log(__FUNCTION__)
#define LogThread() mozilla::widget::WinUtils::Log("%s: IsMainThread:%d ThreadId:%X", __FUNCTION__, NS_IsMainThread(), GetCurrentThreadId())
#define LogThis() mozilla::widget::WinUtils::Log("[%X] %s", this, __FUNCTION__)
#define LogException(e) mozilla::widget::WinUtils::Log("%s Exception:%s", __FUNCTION__, e->ToString()->Data())
#define LogHRESULT(hr) mozilla::widget::WinUtils::Log("%s hr=%X", __FUNCTION__, hr)
#ifdef MOZ_PLACES
class myDownloadObserver final : public nsIDownloadObserver
{
~myDownloadObserver() {}
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOWNLOADOBSERVER
};
#endif
class WinUtils
{
// Function pointers for APIs that may not be available depending on
// the Win10 update version -- will be set up in Initialize().
static SetThreadDpiAwarenessContextProc sSetThreadDpiAwarenessContext;
static EnableNonClientDpiScalingProc sEnableNonClientDpiScaling;
public:
class AutoSystemDpiAware
{
public:
AutoSystemDpiAware()
{
if (sSetThreadDpiAwarenessContext) {
mPrevContext = sSetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE);
}
}
~AutoSystemDpiAware()
{
if (sSetThreadDpiAwarenessContext) {
sSetThreadDpiAwarenessContext(mPrevContext);
}
}
private:
DPI_AWARENESS_CONTEXT mPrevContext;
};
// Wrapper for DefWindowProc that will enable non-client dpi scaling on the
// window during creation.
static LRESULT WINAPI
NonClientDpiScalingDefWindowProcW(HWND hWnd, UINT msg,
WPARAM wParam, LPARAM lParam);
/**
* Get the system's default logical-to-physical DPI scaling factor,
* which is based on the primary display. Note however that unlike
* LogToPhysFactor(GetPrimaryMonitor()), this will not change during
* a session even if the displays are reconfigured. This scale factor
* is used by Windows theme metrics etc, which do not fully support
* dynamic resolution changes but are only updated on logout.
*/
static double SystemScaleFactor();
static bool IsPerMonitorDPIAware();
/**
* Functions to convert between logical pixels as used by most Windows APIs
* and physical (device) pixels.
*/
static double LogToPhysFactor(HMONITOR aMonitor);
static double LogToPhysFactor(HWND aWnd) {
// if there's an ancestor window, we want to share its DPI setting
HWND ancestor = ::GetAncestor(aWnd, GA_ROOTOWNER);
return LogToPhysFactor(::MonitorFromWindow(ancestor ? ancestor : aWnd,
MONITOR_DEFAULTTOPRIMARY));
}
static double LogToPhysFactor(HDC aDC) {
return LogToPhysFactor(::WindowFromDC(aDC));
}
static int32_t LogToPhys(HMONITOR aMonitor, double aValue);
static HMONITOR GetPrimaryMonitor();
static HMONITOR MonitorFromRect(const gfx::Rect& rect);
/**
* Logging helpers that dump output to prlog module 'Widget', console, and
* OutputDebugString. Note these output in both debug and release builds.
*/
static void Log(const char *fmt, ...);
static void LogW(const wchar_t *fmt, ...);
/**
* PeekMessage() and GetMessage() are wrapper methods for PeekMessageW(),
* GetMessageW(), ITfMessageMgr::PeekMessageW() and
* ITfMessageMgr::GetMessageW().
* Don't call the native APIs directly. You MUST use these methods instead.
*/
static bool PeekMessage(LPMSG aMsg, HWND aWnd, UINT aFirstMessage,
UINT aLastMessage, UINT aOption);
static bool GetMessage(LPMSG aMsg, HWND aWnd, UINT aFirstMessage,
UINT aLastMessage);
/**
* Wait until a message is ready to be processed.
* Prefer using this method to directly calling ::WaitMessage since
* ::WaitMessage will wait if there is an unread message in the queue.
* That can cause freezes until another message enters the queue if the
* message is marked read by a call to PeekMessage which the caller is
* not aware of (e.g., from a different thread).
* Note that this method may cause sync dispatch of sent (as opposed to
* posted) messages.
* @param aTimeoutMs Timeout for waiting in ms, defaults to INFINITE
*/
static void WaitForMessage(DWORD aTimeoutMs = INFINITE);
/**
* Gets the value of a string-typed registry value.
*
* @param aRoot The registry root to search in.
* @param aKeyName The name of the registry key to open.
* @param aValueName The name of the registry value in the specified key whose
* value is to be retrieved. Can be null, to retrieve the key's unnamed/
* default value.
* @param aBuffer The buffer into which to store the string value. Can be
* null, in which case the return value indicates just whether the value
* exists.
* @param aBufferLength The size of aBuffer, in bytes.
* @return Whether the value exists and is a string.
*/
static bool GetRegistryKey(HKEY aRoot,
char16ptr_t aKeyName,
char16ptr_t aValueName,
wchar_t* aBuffer,
DWORD aBufferLength);
/**
* Checks whether the registry key exists in either 32bit or 64bit branch on
* the environment.
*
* @param aRoot The registry root of aName.
* @param aKeyName The name of the registry key to check.
* @return TRUE if it exists and is readable. Otherwise, FALSE.
*/
static bool HasRegistryKey(HKEY aRoot,
char16ptr_t aKeyName);
/**
* GetTopLevelHWND() returns a window handle of the top level window which
* aWnd belongs to. Note that the result may not be our window, i.e., it
* may not be managed by nsWindow.
*
* See follwing table for the detail of the result window type.
*
* +-------------------------+-----------------------------------------------+
* | | aStopIfNotPopup |
* +-------------------------+-----------------------+-----------------------+
* | | TRUE | FALSE |
+ +-----------------+-------+-----------------------+-----------------------+
* | | | * an independent top level window |
* | | TRUE | * a pupup window (WS_POPUP) |
* | | | * an owned top level window (like dialog) |
* | aStopIfNotChild +-------+-----------------------+-----------------------+
* | | | * independent window | * only an independent |
* | | FALSE | * non-popup-owned- | top level window |
* | | | window like dialog | |
* +-----------------+-------+-----------------------+-----------------------+
*/
static HWND GetTopLevelHWND(HWND aWnd,
bool aStopIfNotChild = false,
bool aStopIfNotPopup = true);
/**
* SetNSWindowBasePtr() associates an nsWindowBase to aWnd. If aWidget is
* nullptr, it dissociate any nsBaseWidget pointer from aWnd.
* GetNSWindowBasePtr() returns an nsWindowBase pointer which was associated by
* SetNSWindowBasePtr().
* GetNSWindowPtr() is a legacy api for win32 nsWindow and should be avoided
* outside of nsWindow src.
*/
static bool SetNSWindowBasePtr(HWND aWnd, nsWindowBase* aWidget);
static nsWindowBase* GetNSWindowBasePtr(HWND aWnd);
static nsWindow* GetNSWindowPtr(HWND aWnd);
/**
* GetMonitorCount() returns count of monitors on the environment.
*/
static int32_t GetMonitorCount();
/**
* IsOurProcessWindow() returns TRUE if aWnd belongs our process.
* Otherwise, FALSE.
*/
static bool IsOurProcessWindow(HWND aWnd);
/**
* FindOurProcessWindow() returns the nearest ancestor window which
* belongs to our process. If it fails to find our process's window by the
* top level window, returns nullptr. And note that this is using
* ::GetParent() for climbing the window hierarchy, therefore, it gives
* up at an owned top level window except popup window (e.g., dialog).
*/
static HWND FindOurProcessWindow(HWND aWnd);
/**
* FindOurWindowAtPoint() returns the topmost child window which belongs to
* our process's top level window.
*
* NOTE: the topmost child window may NOT be our process's window like a
* plugin's window.
*/
static HWND FindOurWindowAtPoint(const POINT& aPointInScreen);
/**
* InitMSG() returns an MSG struct which was initialized by the params.
* Don't trust the other members in the result.
*/
static MSG InitMSG(UINT aMessage, WPARAM wParam, LPARAM lParam, HWND aWnd);
/**
* GetScanCode() returns a scan code for the LPARAM of WM_KEYDOWN, WM_KEYUP,
* WM_CHAR and WM_UNICHAR.
*
*/
static WORD GetScanCode(LPARAM aLParam)
{
return (aLParam >> 16) & 0xFF;
}
/**
* IsExtendedScanCode() returns TRUE if the LPARAM indicates the key message
* is an extended key event.
*/
static bool IsExtendedScanCode(LPARAM aLParam)
{
return (aLParam & 0x1000000) != 0;
}
/**
* GetInternalMessage() converts a native message to an internal message.
* If there is no internal message for the given native message, returns
* the native message itself.
*/
static UINT GetInternalMessage(UINT aNativeMessage);
/**
* GetNativeMessage() converts an internal message to a native message.
* If aInternalMessage is a native message, returns the native message itself.
*/
static UINT GetNativeMessage(UINT aInternalMessage);
/**
* GetMouseInputSource() returns a pointing device information. The value is
* one of nsIDOMMouseEvent::MOZ_SOURCE_*. This method MUST be called during
* mouse message handling.
*/
static uint16_t GetMouseInputSource();
/**
* Windows also fires mouse window messages for pens and touches, so we should
* retrieve their pointer ID on receiving mouse events as well. Please refer to
* https://msdn.microsoft.com/en-us/library/windows/desktop/ms703320(v=vs.85).aspx
*/
static uint16_t GetMousePointerID();
static bool GetIsMouseFromTouch(EventMessage aEventType);
/**
* SHCreateItemFromParsingName() calls native SHCreateItemFromParsingName()
* API which is available on Vista and up.
*/
static HRESULT SHCreateItemFromParsingName(PCWSTR pszPath, IBindCtx *pbc,
REFIID riid, void **ppv);
/**
* SHGetKnownFolderPath() calls native SHGetKnownFolderPath()
* API which is available on Vista and up.
*/
static HRESULT SHGetKnownFolderPath(REFKNOWNFOLDERID rfid,
DWORD dwFlags,
HANDLE hToken,
PWSTR *ppszPath);
/**
* GetShellItemPath return the file or directory path of a shell item.
* Internally calls IShellItem's GetDisplayName.
*
* aItem the shell item containing the path.
* aResultString the resulting string path.
* returns true if a path was retreived.
*/
static bool GetShellItemPath(IShellItem* aItem,
nsString& aResultString);
/**
* ConvertHRGNToRegion converts a Windows HRGN to an nsIntRegion.
*
* aRgn the HRGN to convert.
* returns the nsIntRegion.
*/
static nsIntRegion ConvertHRGNToRegion(HRGN aRgn);
/**
* ToIntRect converts a Windows RECT to a nsIntRect.
*
* aRect the RECT to convert.
* returns the nsIntRect.
*/
static nsIntRect ToIntRect(const RECT& aRect);
/**
* Helper used in invalidating flash plugin windows owned
* by low rights flash containers.
*/
static void InvalidatePluginAsWorkaround(nsIWidget* aWidget,
const LayoutDeviceIntRect& aRect);
/**
* Returns true if the context or IME state is enabled. Otherwise, false.
*/
static bool IsIMEEnabled(const InputContext& aInputContext);
static bool IsIMEEnabled(IMEState::Enabled aIMEState);
/**
* Returns modifier key array for aModifiers. This is for
* nsIWidget::SynthethizeNative*Event().
*/
static void SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray,
uint32_t aModifiers);
/**
* Does device have touch support
*/
static uint32_t IsTouchDeviceSupportPresent();
/**
* The maximum number of simultaneous touch contacts supported by the device.
* In the case of devices with multiple digitizers (e.g. multiple touch screens),
* the value will be the maximum of the set of maximum supported contacts by
* each individual digitizer.
*/
static uint32_t GetMaxTouchPoints();
/**
* Fully resolves a path to its final path name. So if path contains
* junction points or symlinks to other folders, we'll resolve the path
* fully to the actual path that the links target.
*
* @param aPath path to be resolved.
* @return true if successful, including if nothing needs to be changed.
* false if something failed or aPath does not exist, aPath will
* remain unchanged.
*/
static bool ResolveJunctionPointsAndSymLinks(std::wstring& aPath);
/**
* dwmapi.dll function typedefs and declarations
*/
typedef HRESULT (WINAPI*DwmExtendFrameIntoClientAreaProc)(HWND hWnd, const MARGINS *pMarInset);
typedef HRESULT (WINAPI*DwmIsCompositionEnabledProc)(BOOL *pfEnabled);
typedef HRESULT (WINAPI*DwmSetIconicThumbnailProc)(HWND hWnd, HBITMAP hBitmap, DWORD dwSITFlags);
typedef HRESULT (WINAPI*DwmSetIconicLivePreviewBitmapProc)(HWND hWnd, HBITMAP hBitmap, POINT *pptClient, DWORD dwSITFlags);
typedef HRESULT (WINAPI*DwmGetWindowAttributeProc)(HWND hWnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute);
typedef HRESULT (WINAPI*DwmSetWindowAttributeProc)(HWND hWnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute);
typedef HRESULT (WINAPI*DwmInvalidateIconicBitmapsProc)(HWND hWnd);
typedef HRESULT (WINAPI*DwmDefWindowProcProc)(HWND hWnd, UINT msg, LPARAM lParam, WPARAM wParam, LRESULT *aRetValue);
typedef HRESULT (WINAPI*DwmGetCompositionTimingInfoProc)(HWND hWnd, DWM_TIMING_INFO *info);
typedef HRESULT (WINAPI*DwmFlushProc)(void);
static DwmExtendFrameIntoClientAreaProc dwmExtendFrameIntoClientAreaPtr;
static DwmIsCompositionEnabledProc dwmIsCompositionEnabledPtr;
static DwmSetIconicThumbnailProc dwmSetIconicThumbnailPtr;
static DwmSetIconicLivePreviewBitmapProc dwmSetIconicLivePreviewBitmapPtr;
static DwmGetWindowAttributeProc dwmGetWindowAttributePtr;
static DwmSetWindowAttributeProc dwmSetWindowAttributePtr;
static DwmInvalidateIconicBitmapsProc dwmInvalidateIconicBitmapsPtr;
static DwmDefWindowProcProc dwmDwmDefWindowProcPtr;
static DwmGetCompositionTimingInfoProc dwmGetCompositionTimingInfoPtr;
static DwmFlushProc dwmFlushProcPtr;
static void Initialize();
static bool ShouldHideScrollbars();
/**
* This function normalizes the input path, converts short filenames to long
* filenames, and substitutes environment variables for system paths.
* The resulting output string length is guaranteed to be <= MAX_PATH.
*/
static bool SanitizePath(const wchar_t* aInputPath, nsAString& aOutput);
/**
* Retrieve a semicolon-delimited list of DLL files derived from AppInit_DLLs
*/
static bool GetAppInitDLLs(nsAString& aOutput);
#ifdef ACCESSIBILITY
static void SetAPCPending();
#endif
private:
typedef HRESULT (WINAPI * SHCreateItemFromParsingNamePtr)(PCWSTR pszPath,
IBindCtx *pbc,
REFIID riid,
void **ppv);
static SHCreateItemFromParsingNamePtr sCreateItemFromParsingName;
typedef HRESULT (WINAPI * SHGetKnownFolderPathPtr)(REFKNOWNFOLDERID rfid,
DWORD dwFlags,
HANDLE hToken,
PWSTR *ppszPath);
static SHGetKnownFolderPathPtr sGetKnownFolderPath;
static void GetWhitelistedPaths(
nsTArray<mozilla::Pair<nsString,nsDependentString>>& aOutput);
};
#ifdef MOZ_PLACES
class AsyncFaviconDataReady final : public nsIFaviconDataCallback
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIFAVICONDATACALLBACK
AsyncFaviconDataReady(nsIURI *aNewURI,
nsCOMPtr<nsIThread> &aIOThread,
const bool aURLShortcut);
nsresult OnFaviconDataNotAvailable(void);
private:
~AsyncFaviconDataReady() {}
nsCOMPtr<nsIURI> mNewURI;
nsCOMPtr<nsIThread> mIOThread;
const bool mURLShortcut;
};
#endif
/**
* Asynchronously tries add the list to the build
*/
class AsyncEncodeAndWriteIcon : public nsIRunnable
{
public:
const bool mURLShortcut;
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIRUNNABLE
// Warning: AsyncEncodeAndWriteIcon assumes ownership of the aData buffer passed in
AsyncEncodeAndWriteIcon(const nsAString &aIconPath,
UniquePtr<uint8_t[]> aData,
uint32_t aStride, uint32_t aWidth, uint32_t aHeight,
const bool aURLShortcut);
private:
virtual ~AsyncEncodeAndWriteIcon();
nsAutoString mIconPath;
UniquePtr<uint8_t[]> mBuffer;
uint32_t mStride;
uint32_t mWidth;
uint32_t mHeight;
};
class AsyncDeleteIconFromDisk : public nsIRunnable
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIRUNNABLE
AsyncDeleteIconFromDisk(const nsAString &aIconPath);
private:
virtual ~AsyncDeleteIconFromDisk();
nsAutoString mIconPath;
};
class AsyncDeleteAllFaviconsFromDisk : public nsIRunnable
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIRUNNABLE
AsyncDeleteAllFaviconsFromDisk(bool aIgnoreRecent = false);
private:
virtual ~AsyncDeleteAllFaviconsFromDisk();
int32_t mIcoNoDeleteSeconds;
bool mIgnoreRecent;
};
class FaviconHelper
{
public:
static const char kJumpListCacheDir[];
static const char kShortcutCacheDir[];
static nsresult ObtainCachedIconFile(nsCOMPtr<nsIURI> aFaviconPageURI,
nsString &aICOFilePath,
nsCOMPtr<nsIThread> &aIOThread,
bool aURLShortcut);
static nsresult HashURI(nsCOMPtr<nsICryptoHash> &aCryptoHash,
nsIURI *aUri,
nsACString& aUriHash);
static nsresult GetOutputIconPath(nsCOMPtr<nsIURI> aFaviconPageURI,
nsCOMPtr<nsIFile> &aICOFile,
bool aURLShortcut);
static nsresult
CacheIconFileFromFaviconURIAsync(nsCOMPtr<nsIURI> aFaviconPageURI,
nsCOMPtr<nsIFile> aICOFile,
nsCOMPtr<nsIThread> &aIOThread,
bool aURLShortcut);
static int32_t GetICOCacheSecondsTimeout();
};
} // namespace widget
} // namespace mozilla
#endif // mozilla_widget_WinUtils_h__

View file

@ -0,0 +1,129 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WindowHook.h"
#include "nsWindow.h"
#include "nsWindowDefs.h"
namespace mozilla {
namespace widget {
nsresult
WindowHook::AddHook(UINT nMsg, Callback callback, void *context) {
MessageData *data = LookupOrCreate(nMsg);
if (!data)
return NS_ERROR_OUT_OF_MEMORY;
// Ensure we don't overwrite another hook
NS_ENSURE_TRUE(nullptr == data->hook.cb, NS_ERROR_UNEXPECTED);
data->hook = CallbackData(callback, context);
return NS_OK;
}
nsresult
WindowHook::RemoveHook(UINT nMsg, Callback callback, void *context) {
CallbackData cbdata(callback, context);
MessageData *data = Lookup(nMsg);
if (!data)
return NS_ERROR_UNEXPECTED;
if (data->hook != cbdata)
return NS_ERROR_UNEXPECTED;
data->hook = CallbackData();
DeleteIfEmpty(data);
return NS_OK;
}
nsresult
WindowHook::AddMonitor(UINT nMsg, Callback callback, void *context) {
MessageData *data = LookupOrCreate(nMsg);
return (data && data->monitors.AppendElement(CallbackData(callback, context)))
? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
nsresult
WindowHook::RemoveMonitor(UINT nMsg, Callback callback, void *context) {
CallbackData cbdata(callback, context);
MessageData *data = Lookup(nMsg);
if (!data)
return NS_ERROR_UNEXPECTED;
CallbackDataArray::index_type idx = data->monitors.IndexOf(cbdata);
if (idx == CallbackDataArray::NoIndex)
return NS_ERROR_UNEXPECTED;
data->monitors.RemoveElementAt(idx);
DeleteIfEmpty(data);
return NS_OK;
}
WindowHook::MessageData *
WindowHook::Lookup(UINT nMsg) {
MessageDataArray::index_type idx;
for (idx = 0; idx < mMessageData.Length(); idx++) {
MessageData &data = mMessageData[idx];
if (data.nMsg == nMsg)
return &data;
}
return nullptr;
}
WindowHook::MessageData *
WindowHook::LookupOrCreate(UINT nMsg) {
MessageData *data = Lookup(nMsg);
if (!data) {
data = mMessageData.AppendElement();
if (!data)
return nullptr;
data->nMsg = nMsg;
}
return data;
}
void
WindowHook::DeleteIfEmpty(MessageData *data) {
// Never remove a MessageData that has still a hook or monitor entries.
if (data->hook || !data->monitors.IsEmpty())
return;
MessageDataArray::index_type idx;
idx = data - mMessageData.Elements();
NS_ASSERTION(idx < mMessageData.Length(), "Attempted to delete MessageData that doesn't belong to this array!");
mMessageData.RemoveElementAt(idx);
}
bool
WindowHook::Notify(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam,
MSGResult& aResult)
{
MessageData *data = Lookup(nMsg);
if (!data)
return false;
uint32_t length = data->monitors.Length();
for (uint32_t midx = 0; midx < length; midx++) {
data->monitors[midx].Invoke(hWnd, nMsg, wParam, lParam, &aResult.mResult);
}
aResult.mConsumed =
data->hook.Invoke(hWnd, nMsg, wParam, lParam, &aResult.mResult);
return aResult.mConsumed;
}
bool
WindowHook::CallbackData::Invoke(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam,
LRESULT *aResult) {
if (!cb)
return false;
return cb(context, hWnd, msg, wParam, lParam, aResult);
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,81 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __mozilla_WindowHook_h__
#define __mozilla_WindowHook_h__
#include <windows.h>
#include <nsHashKeys.h>
#include <nsClassHashtable.h>
#include <nsTArray.h>
#include "nsAppShell.h"
class nsWindow;
namespace mozilla {
namespace widget {
struct MSGResult;
class WindowHook {
public:
// It is expected that most callbacks will return false
typedef bool (*Callback)(void *aContext, HWND hWnd, UINT nMsg,
WPARAM wParam, LPARAM lParam, LRESULT *aResult);
nsresult AddHook(UINT nMsg, Callback callback, void *context);
nsresult RemoveHook(UINT nMsg, Callback callback, void *context);
nsresult AddMonitor(UINT nMsg, Callback callback, void *context);
nsresult RemoveMonitor(UINT nMsg, Callback callback, void *context);
private:
struct CallbackData {
Callback cb;
void *context;
CallbackData() : cb(nullptr), context(nullptr) {}
CallbackData(Callback cb, void *ctx) : cb(cb), context(ctx) {}
bool Invoke(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam,
LRESULT *aResult);
bool operator== (const CallbackData &rhs) const {
return cb == rhs.cb && context == rhs.context;
}
bool operator!= (const CallbackData &rhs) const {
return !(*this == rhs);
}
operator bool () const {
return !!cb;
}
};
typedef nsTArray<CallbackData> CallbackDataArray;
struct MessageData {
UINT nMsg;
CallbackData hook;
CallbackDataArray monitors;
};
bool Notify(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam,
MSGResult& aResult);
MessageData *Lookup(UINT nMsg);
MessageData *LookupOrCreate(UINT nMsg);
void DeleteIfEmpty(MessageData *data);
typedef nsTArray<MessageData> MessageDataArray;
MessageDataArray mMessageData;
// For Notify
friend class ::nsWindow;
};
}
}
#endif // __mozilla_WindowHook_h__

View file

@ -0,0 +1,182 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <windows.h>
#include <winsdkver.h>
#include "mozwrlbase.h"
#include "nsServiceManagerUtils.h"
#include "WindowsUIUtils.h"
#include "nsIObserverService.h"
#include "nsIBaseWindow.h"
#include "nsIDocShell.h"
#include "nsIAppShellService.h"
#include "nsAppShellCID.h"
#include "nsIXULWindow.h"
#include "mozilla/Services.h"
#include "mozilla/WindowsVersion.h"
#include "nsString.h"
#include "nsIWidget.h"
/* mingw currently doesn't support windows.ui.viewmanagement.h, so we disable it until it's fixed. */
#ifndef __MINGW32__
#include <windows.ui.viewmanagement.h>
#pragma comment(lib, "runtimeobject.lib")
using namespace mozilla;
using namespace ABI::Windows::UI;
using namespace ABI::Windows::UI::ViewManagement;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Foundation;
/* All of this is win10 stuff and we're compiling against win81 headers
* for now, so we may need to do some legwork: */
#if WINVER_MAXVER < 0x0A00
namespace ABI {
namespace Windows {
namespace UI {
namespace ViewManagement {
enum UserInteractionMode {
UserInteractionMode_Mouse = 0,
UserInteractionMode_Touch = 1
};
}
}
}
}
#endif
#ifndef RuntimeClass_Windows_UI_ViewManagement_UIViewSettings
#define RuntimeClass_Windows_UI_ViewManagement_UIViewSettings L"Windows.UI.ViewManagement.UIViewSettings"
#endif
#if WINVER_MAXVER < 0x0A00
namespace ABI {
namespace Windows {
namespace UI {
namespace ViewManagement {
interface IUIViewSettings;
MIDL_INTERFACE("C63657F6-8850-470D-88F8-455E16EA2C26")
IUIViewSettings : public IInspectable
{
public:
virtual HRESULT STDMETHODCALLTYPE get_UserInteractionMode(UserInteractionMode *value) = 0;
};
extern const __declspec(selectany) IID & IID_IUIViewSettings = __uuidof(IUIViewSettings);
}
}
}
}
#endif
#ifndef IUIViewSettingsInterop
typedef interface IUIViewSettingsInterop IUIViewSettingsInterop;
MIDL_INTERFACE("3694dbf9-8f68-44be-8ff5-195c98ede8a6")
IUIViewSettingsInterop : public IInspectable
{
public:
virtual HRESULT STDMETHODCALLTYPE GetForWindow(HWND hwnd, REFIID riid, void **ppv) = 0;
};
#endif
#endif
WindowsUIUtils::WindowsUIUtils() :
mInTabletMode(eTabletModeUnknown)
{
}
WindowsUIUtils::~WindowsUIUtils()
{
}
/*
* Implement the nsISupports methods...
*/
NS_IMPL_ISUPPORTS(WindowsUIUtils,
nsIWindowsUIUtils)
NS_IMETHODIMP
WindowsUIUtils::GetInTabletMode(bool* aResult)
{
if (mInTabletMode == eTabletModeUnknown) {
UpdateTabletModeState();
}
*aResult = mInTabletMode == eTabletModeOn;
return NS_OK;
}
NS_IMETHODIMP
WindowsUIUtils::UpdateTabletModeState()
{
#ifndef __MINGW32__
if (!IsWin10OrLater()) {
return NS_OK;
}
nsCOMPtr<nsIAppShellService> appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
nsCOMPtr<nsIXULWindow> hiddenWindow;
nsresult rv = appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow));
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsIDocShell> docShell;
rv = hiddenWindow->GetDocShell(getter_AddRefs(docShell));
if (NS_FAILED(rv) || !docShell) {
return rv;
}
nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(docShell));
if (!baseWindow)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIWidget> widget;
baseWindow->GetMainWidget(getter_AddRefs(widget));
if (!widget)
return NS_ERROR_FAILURE;
HWND winPtr = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW);
ComPtr<IUIViewSettingsInterop> uiViewSettingsInterop;
HRESULT hr = GetActivationFactory(
HStringReference(RuntimeClass_Windows_UI_ViewManagement_UIViewSettings).Get(),
&uiViewSettingsInterop);
if (SUCCEEDED(hr)) {
ComPtr<IUIViewSettings> uiViewSettings;
hr = uiViewSettingsInterop->GetForWindow(winPtr, IID_PPV_ARGS(&uiViewSettings));
if (SUCCEEDED(hr)) {
UserInteractionMode mode;
hr = uiViewSettings->get_UserInteractionMode(&mode);
if (SUCCEEDED(hr)) {
TabletModeState oldTabletModeState = mInTabletMode;
mInTabletMode = (mode == UserInteractionMode_Touch) ? eTabletModeOn : eTabletModeOff;
if (mInTabletMode != oldTabletModeState) {
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
NS_NAMED_LITERAL_STRING(tabletMode, "tablet-mode");
NS_NAMED_LITERAL_STRING(normalMode, "normal-mode");
observerService->NotifyObservers(nullptr, "tablet-mode-change",
((mInTabletMode == eTabletModeOn) ? tabletMode.get() : normalMode.get()));
}
}
}
}
#endif
return NS_OK;
}

View file

@ -0,0 +1,29 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_widget_WindowsUIUtils_h__
#define mozilla_widget_WindowsUIUtils_h__
#include "nsIWindowsUIUtils.h"
enum TabletModeState {
eTabletModeUnknown = 0,
eTabletModeOff,
eTabletModeOn
};
class WindowsUIUtils final : public nsIWindowsUIUtils {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIWINDOWSUIUTILS
WindowsUIUtils();
protected:
~WindowsUIUtils();
TabletModeState mInTabletMode;
};
#endif // mozilla_widget_WindowsUIUtils_h__

123
widget/windows/moz.build Normal file
View file

@ -0,0 +1,123 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
TEST_DIRS += ['tests']
EXPORTS += [
'nsdefs.h',
'WindowHook.h',
'WinUtils.h',
]
EXPORTS.mozilla.widget += [
'AudioSession.h',
'CompositorWidgetChild.h',
'CompositorWidgetParent.h',
'InProcessWinCompositorWidget.h',
'WinCompositorWidget.h',
'WinMessages.h',
'WinModifierKeyState.h',
'WinNativeEventData.h',
]
UNIFIED_SOURCES += [
'AudioSession.cpp',
'CompositorWidgetChild.cpp',
'CompositorWidgetParent.cpp',
'GfxInfo.cpp',
'IEnumFE.cpp',
'IMMHandler.cpp',
'InkCollector.cpp',
'InProcessWinCompositorWidget.cpp',
'JumpListItem.cpp',
'KeyboardLayout.cpp',
'nsAppShell.cpp',
'nsClipboard.cpp',
'nsColorPicker.cpp',
'nsDataObj.cpp',
'nsDataObjCollection.cpp',
'nsDragService.cpp',
'nsIdleServiceWin.cpp',
'nsImageClipboard.cpp',
'nsLookAndFeel.cpp',
'nsNativeDragSource.cpp',
'nsNativeDragTarget.cpp',
'nsNativeThemeWin.cpp',
'nsScreenManagerWin.cpp',
'nsScreenWin.cpp',
'nsSound.cpp',
'nsToolkit.cpp',
'nsUXThemeData.cpp',
'nsWindow.cpp',
'nsWindowBase.cpp',
'nsWindowDbg.cpp',
'nsWindowGfx.cpp',
'nsWinGesture.cpp',
'TaskbarPreview.cpp',
'TaskbarPreviewButton.cpp',
'TaskbarTabPreview.cpp',
'TaskbarWindowPreview.cpp',
'WidgetTraceEvent.cpp',
'WindowHook.cpp',
'WinIMEHandler.cpp',
'WinTaskbar.cpp',
'WinTextEventDispatcherListener.cpp',
'WinUtils.cpp',
]
# The following files cannot be built in unified mode because of name clashes.
SOURCES += [
'JumpListBuilder.cpp',
'nsBidiKeyboard.cpp',
'nsFilePicker.cpp',
'nsWidgetFactory.cpp',
'WinCompositorWidget.cpp',
'WindowsUIUtils.cpp',
'WinMouseScrollHandler.cpp',
]
if CONFIG['MOZ_CRASHREPORTER']:
UNIFIED_SOURCES += [
'LSPAnnotator.cpp',
]
if CONFIG['NS_PRINTING']:
UNIFIED_SOURCES += [
'nsDeviceContextSpecWin.cpp',
'nsPrintOptionsWin.cpp',
'nsPrintSettingsWin.cpp',
]
if CONFIG['NS_ENABLE_TSF']:
SOURCES += [
'TSFTextStore.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'/layout/generic',
'/layout/xul',
'/toolkit/xre',
'/widget',
'/xpcom/base',
]
DEFINES['MOZ_UNICODE'] = True
for var in ('MOZ_ENABLE_D3D10_LAYER'):
if CONFIG[var]:
DEFINES[var] = True
RESFILE = 'widget.res'
CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
OS_LIBS += [
'rpcrt4',
]

View file

@ -0,0 +1,77 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#pragma once
/*
* Includes <wrl.h> and it's children. Defines imports needed by
* corewrappers.h in the case where windows.h has already been
* included w/WINVER < 0x600. Also ups WINVER/_WIN32_WINNT prior
* to including wrl.h. Mozilla's build currently has WINVER set to
* 0x502 for XP support.
*/
#if _WIN32_WINNT < 0x600
#include <windows.h>
VOID
WINAPI
ReleaseSRWLockExclusive(
_Inout_ PSRWLOCK SRWLock
);
VOID
WINAPI
ReleaseSRWLockShared(
_Inout_ PSRWLOCK SRWLock
);
BOOL
WINAPI
InitializeCriticalSectionEx(
_Out_ LPCRITICAL_SECTION lpCriticalSection,
_In_ DWORD dwSpinCount,
_In_ DWORD Flags
);
VOID
WINAPI
InitializeSRWLock(
_Out_ PSRWLOCK SRWLock
);
VOID
WINAPI
AcquireSRWLockExclusive(
_Inout_ PSRWLOCK SRWLock
);
BOOLEAN
WINAPI
TryAcquireSRWLockExclusive(
_Inout_ PSRWLOCK SRWLock
);
BOOLEAN
WINAPI
TryAcquireSRWLockShared(
_Inout_ PSRWLOCK SRWLock
);
VOID
WINAPI
AcquireSRWLockShared(
_Inout_ PSRWLOCK SRWLock
);
#undef WINVER
#undef _WIN32_WINNT
#define WINVER 0x600
#define _WIN32_WINNT 0x600
#endif // _WIN32_WINNT < 0x600
#include <wrl.h>

View file

@ -0,0 +1,436 @@
/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/ipc/MessageChannel.h"
#include "mozilla/ipc/WindowsMessageLoop.h"
#include "nsAppShell.h"
#include "nsToolkit.h"
#include "nsThreadUtils.h"
#include "WinUtils.h"
#include "WinTaskbar.h"
#include "WinMouseScrollHandler.h"
#include "nsWindowDefs.h"
#include "nsString.h"
#include "WinIMEHandler.h"
#include "mozilla/widget/AudioSession.h"
#include "mozilla/HangMonitor.h"
#include "nsIDOMWakeLockListener.h"
#include "nsIPowerManagerService.h"
#include "mozilla/StaticPtr.h"
#include "nsTHashtable.h"
#include "nsHashKeys.h"
#include "GeckoProfiler.h"
#include "nsComponentManagerUtils.h"
#include "nsITimer.h"
// These are two messages that the code in winspool.drv on Windows 7 explicitly
// waits for while it is pumping other Windows messages, during display of the
// Printer Properties dialog.
#define MOZ_WM_PRINTER_PROPERTIES_COMPLETION 0x5b7a
#define MOZ_WM_PRINTER_PROPERTIES_FAILURE 0x5b7f
using namespace mozilla;
using namespace mozilla::widget;
#define WAKE_LOCK_LOG(...) MOZ_LOG(GetWinWakeLockLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
PRLogModuleInfo* GetWinWakeLockLog() {
static PRLogModuleInfo* log = nullptr;
if (!log) {
log = PR_NewLogModule("WinWakeLock");
}
return log;
}
// A wake lock listener that disables screen saver when requested by
// Gecko. For example when we're playing video in a foreground tab we
// don't want the screen saver to turn on.
class WinWakeLockListener final : public nsIDOMMozWakeLockListener
, public nsITimerCallback {
public:
NS_DECL_ISUPPORTS;
NS_IMETHOD Notify(nsITimer *timer) override {
WAKE_LOCK_LOG("WinWakeLock: periodic timer fired");
ResetScreenSaverTimeout();
return NS_OK;
}
private:
~WinWakeLockListener() {}
NS_IMETHOD Callback(const nsAString& aTopic, const nsAString& aState) {
if (!aTopic.EqualsASCII("screen")) {
return NS_OK;
}
// Note the wake lock code ensures that we're not sent duplicate
// "locked-foreground" notifications when multipe wake locks are held.
if (aState.EqualsASCII("locked-foreground")) {
WAKE_LOCK_LOG("WinWakeLock: Blocking screen saver");
// We block the screen saver by periodically resetting the screen
// saver timeout.
StartTimer();
// Prevent the display turning off. On Win7 and later this also
// blocks the screen saver, but we need the timer started above
// to block on Win XP and Vista.
SetThreadExecutionState(ES_DISPLAY_REQUIRED|ES_CONTINUOUS);
} else {
WAKE_LOCK_LOG("WinWakeLock: Unblocking screen saver");
// Re-enable screen saver.
StopTimer();
// Unblock display turning off.
SetThreadExecutionState(ES_CONTINUOUS);
}
return NS_OK;
}
void StartTimer() {
ResetScreenSaverTimeout();
MOZ_ASSERT(!mTimer);
if (mTimer) {
return;
}
nsresult rv;
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to create screen saver timeout reset timer");
return;
}
// The minimum screensaver timeout that can be specified with Windows' UI
// is 60 seconds. We set a timer to re-jig the screen saver 10 seconds
// before we expect the timer to run out, but always at least in 1 second
// intervals. We reset the timer at a max of 50 seconds, so that if the
// user changes the timeout using the UI, we won't be caught out.
int32_t timeout = std::max(std::min(50, (int32_t)mScreenSaverTimeout - 10), 1);
uint32_t timeoutMs = (uint32_t)timeout * 1000;
WAKE_LOCK_LOG("WinWakeLock: Setting periodic timer for %d ms", timeoutMs);
rv = timer->InitWithCallback(this,
timeoutMs,
nsITimer::TYPE_REPEATING_SLACK);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to initialize screen saver timeout reset timer");
return;
}
mTimer = timer.forget();
}
void StopTimer() {
WAKE_LOCK_LOG("WinWakeLock: StopTimer()");
if (!mTimer) {
return;
}
mTimer->Cancel();
mTimer = nullptr;
}
// Resets the operating system's timeout for when to disable the screen.
// Called periodically to keep the screensaver off.
void ResetScreenSaverTimeout() {
if (SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0, &mScreenSaverTimeout, 0)) {
SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, mScreenSaverTimeout, NULL, 0);
}
WAKE_LOCK_LOG("WinWakeLock: ResetScreenSaverTimeout() mScreenSaverTimeout=%d", mScreenSaverTimeout);
}
UINT mScreenSaverTimeout = 60;
nsCOMPtr<nsITimer> mTimer;
};
NS_IMPL_ISUPPORTS(WinWakeLockListener, nsIDOMMozWakeLockListener, nsITimerCallback)
StaticRefPtr<WinWakeLockListener> sWakeLockListener;
static void
AddScreenWakeLockListener()
{
nsCOMPtr<nsIPowerManagerService> sPowerManagerService = do_GetService(POWERMANAGERSERVICE_CONTRACTID);
if (sPowerManagerService) {
sWakeLockListener = new WinWakeLockListener();
sPowerManagerService->AddWakeLockListener(sWakeLockListener);
} else {
NS_WARNING("Failed to retrieve PowerManagerService, wakelocks will be broken!");
}
}
static void
RemoveScreenWakeLockListener()
{
nsCOMPtr<nsIPowerManagerService> sPowerManagerService = do_GetService(POWERMANAGERSERVICE_CONTRACTID);
if (sPowerManagerService) {
sPowerManagerService->RemoveWakeLockListener(sWakeLockListener);
sPowerManagerService = nullptr;
sWakeLockListener = nullptr;
}
}
namespace mozilla {
namespace widget {
// Native event callback message.
UINT sAppShellGeckoMsgId = RegisterWindowMessageW(L"nsAppShell:EventID");
} }
const wchar_t* kTaskbarButtonEventId = L"TaskbarButtonCreated";
UINT sTaskbarButtonCreatedMsg;
/* static */
UINT nsAppShell::GetTaskbarButtonCreatedMessage() {
return sTaskbarButtonCreatedMsg;
}
namespace mozilla {
namespace crashreporter {
void LSPAnnotate();
} // namespace crashreporter
} // namespace mozilla
using mozilla::crashreporter::LSPAnnotate;
//-------------------------------------------------------------------------
/*static*/ LRESULT CALLBACK
nsAppShell::EventWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == sAppShellGeckoMsgId) {
nsAppShell *as = reinterpret_cast<nsAppShell *>(lParam);
as->NativeEventCallback();
NS_RELEASE(as);
return TRUE;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
nsAppShell::~nsAppShell()
{
if (mEventWnd) {
// DestroyWindow doesn't do anything when called from a non UI thread.
// Since mEventWnd was created on the UI thread, it must be destroyed on
// the UI thread.
SendMessage(mEventWnd, WM_CLOSE, 0, 0);
}
}
nsresult
nsAppShell::Init()
{
#ifdef MOZ_CRASHREPORTER
LSPAnnotate();
#endif
mLastNativeEventScheduled = TimeStamp::NowLoRes();
mozilla::ipc::windows::InitUIThread();
sTaskbarButtonCreatedMsg = ::RegisterWindowMessageW(kTaskbarButtonEventId);
NS_ASSERTION(sTaskbarButtonCreatedMsg, "Could not register taskbar button creation message");
WNDCLASSW wc;
HINSTANCE module = GetModuleHandle(nullptr);
const wchar_t *const kWindowClass = L"nsAppShell:EventWindowClass";
if (!GetClassInfoW(module, kWindowClass, &wc)) {
wc.style = 0;
wc.lpfnWndProc = EventWindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = module;
wc.hIcon = nullptr;
wc.hCursor = nullptr;
wc.hbrBackground = (HBRUSH) nullptr;
wc.lpszMenuName = (LPCWSTR) nullptr;
wc.lpszClassName = kWindowClass;
RegisterClassW(&wc);
}
mEventWnd = CreateWindowW(kWindowClass, L"nsAppShell:EventWindow",
0, 0, 0, 10, 10, nullptr, nullptr, module, nullptr);
NS_ENSURE_STATE(mEventWnd);
return nsBaseAppShell::Init();
}
NS_IMETHODIMP
nsAppShell::Run(void)
{
// Content processes initialize audio later through PContent using audio
// tray id information pulled from the browser process AudioSession. This
// way the two share a single volume control.
// Note StopAudioSession() is called from nsAppRunner.cpp after xpcom is torn
// down to insure the browser shuts down after child processes.
if (XRE_IsParentProcess()) {
mozilla::widget::StartAudioSession();
}
// Add an observer that disables the screen saver when requested by Gecko.
// For example when we're playing video in the foreground tab.
AddScreenWakeLockListener();
nsresult rv = nsBaseAppShell::Run();
RemoveScreenWakeLockListener();
return rv;
}
NS_IMETHODIMP
nsAppShell::Exit(void)
{
return nsBaseAppShell::Exit();
}
void
nsAppShell::DoProcessMoreGeckoEvents()
{
// Called by nsBaseAppShell's NativeEventCallback() after it has finished
// processing pending gecko events and there are still gecko events pending
// for the thread. (This can happen if NS_ProcessPendingEvents reached it's
// starvation timeout limit.) The default behavior in nsBaseAppShell is to
// call ScheduleNativeEventCallback to post a follow up native event callback
// message. This triggers an additional call to NativeEventCallback for more
// gecko event processing.
// There's a deadlock risk here with certain internal Windows modal loops. In
// our dispatch code, we prioritize messages so that input is handled first.
// However Windows modal dispatch loops often prioritize posted messages. If
// we find ourselves in a tight gecko timer loop where NS_ProcessPendingEvents
// takes longer than the timer duration, NS_HasPendingEvents(thread) will
// always be true. ScheduleNativeEventCallback will be called on every
// NativeEventCallback callback, and in a Windows modal dispatch loop, the
// callback message will be processed first -> input gets starved, dead lock.
// To avoid, don't post native callback messages from NativeEventCallback
// when we're in a modal loop. This gets us back into the Windows modal
// dispatch loop dispatching input messages. Once we drop out of the modal
// loop, we use mNativeCallbackPending to fire off a final NativeEventCallback
// if we need it, which insures NS_ProcessPendingEvents gets called and all
// gecko events get processed.
if (mEventloopNestingLevel < 2) {
OnDispatchedEvent(nullptr);
mNativeCallbackPending = false;
} else {
mNativeCallbackPending = true;
}
}
void
nsAppShell::ScheduleNativeEventCallback()
{
// Post a message to the hidden message window
NS_ADDREF_THIS(); // will be released when the event is processed
{
MutexAutoLock lock(mLastNativeEventScheduledMutex);
// Time stamp this event so we can detect cases where the event gets
// dropping in sub classes / modal loops we do not control.
mLastNativeEventScheduled = TimeStamp::NowLoRes();
}
::PostMessage(mEventWnd, sAppShellGeckoMsgId, 0, reinterpret_cast<LPARAM>(this));
}
bool
nsAppShell::ProcessNextNativeEvent(bool mayWait)
{
// Notify ipc we are spinning a (possibly nested) gecko event loop.
mozilla::ipc::MessageChannel::NotifyGeckoEventDispatch();
bool gotMessage = false;
do {
MSG msg;
bool uiMessage = false;
// For avoiding deadlock between our process and plugin process by
// mouse wheel messages, we're handling actually when we receive one of
// following internal messages which is posted by native mouse wheel
// message handler. Any other events, especially native modifier key
// events, should not be handled between native message and posted
// internal message because it may make different modifier key state or
// mouse cursor position between them.
if (mozilla::widget::MouseScrollHandler::IsWaitingInternalMessage()) {
gotMessage = WinUtils::PeekMessage(&msg, nullptr, MOZ_WM_MOUSEWHEEL_FIRST,
MOZ_WM_MOUSEWHEEL_LAST, PM_REMOVE);
NS_ASSERTION(gotMessage,
"waiting internal wheel message, but it has not come");
uiMessage = gotMessage;
}
if (!gotMessage) {
gotMessage = WinUtils::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE);
uiMessage =
(msg.message >= WM_KEYFIRST && msg.message <= WM_IME_KEYLAST) ||
(msg.message >= NS_WM_IMEFIRST && msg.message <= NS_WM_IMELAST) ||
(msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST);
}
if (gotMessage) {
if (msg.message == WM_QUIT) {
::PostQuitMessage(msg.wParam);
Exit();
} else {
// If we had UI activity we would be processing it now so we know we
// have either kUIActivity or kActivityNoUIAVail.
mozilla::HangMonitor::NotifyActivity(
uiMessage ? mozilla::HangMonitor::kUIActivity :
mozilla::HangMonitor::kActivityNoUIAVail);
if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST &&
IMEHandler::ProcessRawKeyMessage(msg)) {
continue; // the message is consumed.
}
// Store Printer Properties messages for reposting, because they are not
// processed by a window procedure, but are explicitly waited for in the
// winspool.drv code that will be further up the stack.
if (msg.message == MOZ_WM_PRINTER_PROPERTIES_COMPLETION ||
msg.message == MOZ_WM_PRINTER_PROPERTIES_FAILURE) {
mMsgsToRepost.push_back(msg);
continue;
}
::TranslateMessage(&msg);
::DispatchMessageW(&msg);
}
} else if (mayWait) {
// Block and wait for any posted application message
mozilla::HangMonitor::Suspend();
{
GeckoProfilerSleepRAII profiler_sleep;
WinUtils::WaitForMessage();
}
}
} while (!gotMessage && mayWait);
// See DoProcessNextNativeEvent, mEventloopNestingLevel will be
// one when a modal loop unwinds.
if (mNativeCallbackPending && mEventloopNestingLevel == 1)
DoProcessMoreGeckoEvents();
// Check for starved native callbacks. If we haven't processed one
// of these events in NATIVE_EVENT_STARVATION_LIMIT, fire one off.
static const mozilla::TimeDuration nativeEventStarvationLimit =
mozilla::TimeDuration::FromSeconds(NATIVE_EVENT_STARVATION_LIMIT);
TimeDuration timeSinceLastNativeEventScheduled;
{
MutexAutoLock lock(mLastNativeEventScheduledMutex);
timeSinceLastNativeEventScheduled =
TimeStamp::NowLoRes() - mLastNativeEventScheduled;
}
if (timeSinceLastNativeEventScheduled > nativeEventStarvationLimit) {
ScheduleNativeEventCallback();
}
return gotMessage;
}
nsresult
nsAppShell::AfterProcessNextEvent(nsIThreadInternal* /* unused */,
bool /* unused */)
{
if (!mMsgsToRepost.empty()) {
for (MSG msg : mMsgsToRepost) {
::PostMessageW(msg.hwnd, msg.message, msg.wParam, msg.lParam);
}
mMsgsToRepost.clear();
}
return NS_OK;
}

View file

@ -0,0 +1,59 @@
/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsAppShell_h__
#define nsAppShell_h__
#include "nsBaseAppShell.h"
#include <windows.h>
#include <vector>
#include "mozilla/TimeStamp.h"
#include "mozilla/Mutex.h"
// The maximum time we allow before forcing a native event callback.
// In seconds.
#define NATIVE_EVENT_STARVATION_LIMIT 1
/**
* Native Win32 Application shell wrapper
*/
class nsAppShell : public nsBaseAppShell
{
public:
nsAppShell() :
mEventWnd(nullptr),
mNativeCallbackPending(false),
mLastNativeEventScheduledMutex("nsAppShell::mLastNativeEventScheduledMutex")
{}
typedef mozilla::TimeStamp TimeStamp;
typedef mozilla::Mutex Mutex;
nsresult Init();
void DoProcessMoreGeckoEvents();
static UINT GetTaskbarButtonCreatedMessage();
NS_IMETHOD AfterProcessNextEvent(nsIThreadInternal* thread,
bool eventWasProcessed) final;
protected:
NS_IMETHOD Run();
NS_IMETHOD Exit();
virtual void ScheduleNativeEventCallback();
virtual bool ProcessNextNativeEvent(bool mayWait);
virtual ~nsAppShell();
static LRESULT CALLBACK EventWindowProc(HWND, UINT, WPARAM, LPARAM);
protected:
HWND mEventWnd;
bool mNativeCallbackPending;
Mutex mLastNativeEventScheduledMutex;
TimeStamp mLastNativeEventScheduled;
std::vector<MSG> mMsgsToRepost;
};
#endif // nsAppShell_h__

View file

@ -0,0 +1,187 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <stdio.h>
#include "nsBidiKeyboard.h"
#include "WidgetUtils.h"
#include "prmem.h"
#include <tchar.h>
NS_IMPL_ISUPPORTS(nsBidiKeyboard, nsIBidiKeyboard)
nsBidiKeyboard::nsBidiKeyboard() : nsIBidiKeyboard()
{
Reset();
}
nsBidiKeyboard::~nsBidiKeyboard()
{
}
NS_IMETHODIMP nsBidiKeyboard::Reset()
{
mInitialized = false;
mHaveBidiKeyboards = false;
mLTRKeyboard[0] = '\0';
mRTLKeyboard[0] = '\0';
mCurrentLocaleName[0] = '\0';
return NS_OK;
}
NS_IMETHODIMP nsBidiKeyboard::IsLangRTL(bool *aIsRTL)
{
*aIsRTL = false;
nsresult result = SetupBidiKeyboards();
if (NS_FAILED(result))
return result;
HKL currentLocale;
currentLocale = ::GetKeyboardLayout(0);
*aIsRTL = IsRTLLanguage(currentLocale);
if (!::GetKeyboardLayoutNameW(mCurrentLocaleName))
return NS_ERROR_FAILURE;
NS_ASSERTION(*mCurrentLocaleName,
"GetKeyboardLayoutName return string length == 0");
NS_ASSERTION((wcslen(mCurrentLocaleName) < KL_NAMELENGTH),
"GetKeyboardLayoutName return string length >= KL_NAMELENGTH");
// The language set by the user overrides the default language for that direction
if (*aIsRTL) {
wcsncpy(mRTLKeyboard, mCurrentLocaleName, KL_NAMELENGTH);
mRTLKeyboard[KL_NAMELENGTH-1] = '\0'; // null terminate
} else {
wcsncpy(mLTRKeyboard, mCurrentLocaleName, KL_NAMELENGTH);
mLTRKeyboard[KL_NAMELENGTH-1] = '\0'; // null terminate
}
NS_ASSERTION((wcslen(mRTLKeyboard) < KL_NAMELENGTH),
"mLTRKeyboard has string length >= KL_NAMELENGTH");
NS_ASSERTION((wcslen(mLTRKeyboard) < KL_NAMELENGTH),
"mRTLKeyboard has string length >= KL_NAMELENGTH");
return NS_OK;
}
NS_IMETHODIMP nsBidiKeyboard::GetHaveBidiKeyboards(bool* aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
nsresult result = SetupBidiKeyboards();
if (NS_FAILED(result))
return result;
*aResult = mHaveBidiKeyboards;
return NS_OK;
}
// Get the list of keyboard layouts available in the system
// Set mLTRKeyboard to the first LTR keyboard in the list and mRTLKeyboard to the first RTL keyboard in the list
// These defaults will be used unless the user explicitly sets something else.
nsresult nsBidiKeyboard::SetupBidiKeyboards()
{
if (mInitialized)
return mHaveBidiKeyboards ? NS_OK : NS_ERROR_FAILURE;
int keyboards;
HKL far* buf;
HKL locale;
wchar_t localeName[KL_NAMELENGTH];
bool isLTRKeyboardSet = false;
bool isRTLKeyboardSet = false;
// GetKeyboardLayoutList with 0 as first parameter returns the number of keyboard layouts available
keyboards = ::GetKeyboardLayoutList(0, nullptr);
if (!keyboards)
return NS_ERROR_FAILURE;
// allocate a buffer to hold the list
buf = (HKL far*) PR_Malloc(keyboards * sizeof(HKL));
if (!buf)
return NS_ERROR_OUT_OF_MEMORY;
// Call again to fill the buffer
if (::GetKeyboardLayoutList(keyboards, buf) != keyboards) {
PR_Free(buf);
return NS_ERROR_UNEXPECTED;
}
// Go through the list and pick a default LTR and RTL keyboard layout
while (keyboards--) {
locale = buf[keyboards];
if (IsRTLLanguage(locale)) {
_snwprintf(mRTLKeyboard, KL_NAMELENGTH, L"%.*x", KL_NAMELENGTH - 1,
LANGIDFROMLCID((DWORD_PTR)locale));
isRTLKeyboardSet = true;
}
else {
_snwprintf(mLTRKeyboard, KL_NAMELENGTH, L"%.*x", KL_NAMELENGTH - 1,
LANGIDFROMLCID((DWORD_PTR)locale));
isLTRKeyboardSet = true;
}
}
PR_Free(buf);
mInitialized = true;
// If there is not at least one keyboard of each directionality, Bidi
// keyboard functionality will be disabled.
mHaveBidiKeyboards = (isRTLKeyboardSet && isLTRKeyboardSet);
if (!mHaveBidiKeyboards)
return NS_ERROR_FAILURE;
// Get the current keyboard layout and use it for either mRTLKeyboard or
// mLTRKeyboard as appropriate. If the user has many keyboard layouts
// installed this prevents us from arbitrarily resetting the current
// layout (bug 80274)
locale = ::GetKeyboardLayout(0);
if (!::GetKeyboardLayoutNameW(localeName))
return NS_ERROR_FAILURE;
NS_ASSERTION(*localeName,
"GetKeyboardLayoutName return string length == 0");
NS_ASSERTION((wcslen(localeName) < KL_NAMELENGTH),
"GetKeyboardLayout return string length >= KL_NAMELENGTH");
if (IsRTLLanguage(locale)) {
wcsncpy(mRTLKeyboard, localeName, KL_NAMELENGTH);
mRTLKeyboard[KL_NAMELENGTH-1] = '\0'; // null terminate
}
else {
wcsncpy(mLTRKeyboard, localeName, KL_NAMELENGTH);
mLTRKeyboard[KL_NAMELENGTH-1] = '\0'; // null terminate
}
NS_ASSERTION(*mRTLKeyboard,
"mLTRKeyboard has string length == 0");
NS_ASSERTION(*mLTRKeyboard,
"mLTRKeyboard has string length == 0");
return NS_OK;
}
// Test whether the language represented by this locale identifier is a
// right-to-left language, using bit 123 of the Unicode subset bitfield in
// the LOCALESIGNATURE
// See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/unicode_63ub.asp
bool nsBidiKeyboard::IsRTLLanguage(HKL aLocale)
{
LOCALESIGNATURE localesig;
return (::GetLocaleInfoW(PRIMARYLANGID((DWORD_PTR)aLocale),
LOCALE_FONTSIGNATURE,
(LPWSTR)&localesig,
(sizeof(localesig)/sizeof(WCHAR))) &&
(localesig.lsUsb[3] & 0x08000000));
}
//static
void
nsBidiKeyboard::OnLayoutChange()
{
mozilla::widget::WidgetUtils::SendBidiKeyboardInfoToContent();
}

View file

@ -0,0 +1,37 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __nsBidiKeyboard
#define __nsBidiKeyboard
#include "nsIBidiKeyboard.h"
#include <windows.h>
class nsBidiKeyboard : public nsIBidiKeyboard
{
virtual ~nsBidiKeyboard();
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIBIDIKEYBOARD
nsBidiKeyboard();
static void OnLayoutChange();
protected:
nsresult SetupBidiKeyboards();
bool IsRTLLanguage(HKL aLocale);
bool mInitialized;
bool mHaveBidiKeyboards;
wchar_t mLTRKeyboard[KL_NAMELENGTH];
wchar_t mRTLKeyboard[KL_NAMELENGTH];
wchar_t mCurrentLocaleName[KL_NAMELENGTH];
};
#endif // __nsBidiKeyboard

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,92 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsClipboard_h__
#define nsClipboard_h__
#include "nsBaseClipboard.h"
#include "nsIObserver.h"
#include "nsIURI.h"
#include <windows.h>
class nsITransferable;
class nsIWidget;
class nsIFile;
struct IDataObject;
/**
* Native Win32 Clipboard wrapper
*/
class nsClipboard : public nsBaseClipboard,
public nsIObserver
{
virtual ~nsClipboard();
public:
nsClipboard();
NS_DECL_ISUPPORTS_INHERITED
// nsIObserver
NS_DECL_NSIOBSERVER
// nsIClipboard
NS_IMETHOD HasDataMatchingFlavors(const char** aFlavorList, uint32_t aLength,
int32_t aWhichClipboard, bool *_retval) override;
NS_IMETHOD EmptyClipboard(int32_t aWhichClipboard) override;
// Internal Native Routines
static nsresult CreateNativeDataObject(nsITransferable * aTransferable,
IDataObject ** aDataObj,
nsIURI * uri);
static nsresult SetupNativeDataObject(nsITransferable * aTransferable,
IDataObject * aDataObj);
static nsresult GetDataFromDataObject(IDataObject * aDataObject,
UINT anIndex,
nsIWidget * aWindow,
nsITransferable * aTransferable);
static nsresult GetNativeDataOffClipboard(nsIWidget * aWindow, UINT aIndex, UINT aFormat, void ** aData, uint32_t * aLen);
static nsresult GetNativeDataOffClipboard(IDataObject * aDataObject, UINT aIndex, UINT aFormat, const char * aMIMEImageFormat, void ** aData, uint32_t * aLen);
static nsresult GetGlobalData(HGLOBAL aHGBL, void ** aData, uint32_t * aLen);
// This function returns the internal Windows clipboard format identifier
// for a given Mime string. The default is to map kHTMLMime ("text/html")
// to the clipboard format CF_HTML ("HTLM Format"), but it can also be
// registered as clipboard format "text/html" to support previous versions
// of Gecko.
static UINT GetFormat(const char* aMimeStr, bool aMapHTMLMime = true);
static UINT CF_HTML;
static UINT CF_CUSTOMTYPES;
protected:
NS_IMETHOD SetNativeClipboardData ( int32_t aWhichClipboard ) override;
NS_IMETHOD GetNativeClipboardData ( nsITransferable * aTransferable, int32_t aWhichClipboard ) override;
static bool IsInternetShortcut ( const nsAString& inFileName ) ;
static bool FindURLFromLocalFile ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) ;
static bool FindURLFromNativeURL ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) ;
static bool FindUnicodeFromPlainText ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) ;
static bool FindPlatformHTML ( IDataObject* inDataObject, UINT inIndex, void** outData,
uint32_t* outStartOfData, uint32_t* outDataLen );
static void ResolveShortcut ( nsIFile* inFileName, nsACString& outURL ) ;
nsIWidget * mWindow;
};
#define SET_FORMATETC(fe, cf, td, asp, li, med) \
{\
(fe).cfFormat=cf;\
(fe).ptd=td;\
(fe).dwAspect=asp;\
(fe).lindex=li;\
(fe).tymed=med;\
}
#endif // nsClipboard_h__

View file

@ -0,0 +1,212 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsColorPicker.h"
#include <shlwapi.h>
#include "mozilla/AutoRestore.h"
#include "nsIWidget.h"
#include "nsString.h"
#include "WidgetUtils.h"
using namespace mozilla::widget;
namespace
{
// Manages NS_NATIVE_TMP_WINDOW child windows. NS_NATIVE_TMP_WINDOWs are
// temporary child windows of mParentWidget created to address RTL issues
// in picker dialogs. We are responsible for destroying these.
class AutoDestroyTmpWindow
{
public:
explicit AutoDestroyTmpWindow(HWND aTmpWnd) :
mWnd(aTmpWnd) {
}
~AutoDestroyTmpWindow() {
if (mWnd)
DestroyWindow(mWnd);
}
inline HWND get() const { return mWnd; }
private:
HWND mWnd;
};
static DWORD ColorStringToRGB(const nsAString& aColor)
{
DWORD result = 0;
for (uint32_t i = 1; i < aColor.Length(); ++i) {
result *= 16;
char16_t c = aColor[i];
if (c >= '0' && c <= '9') {
result += c - '0';
} else if (c >= 'a' && c <= 'f') {
result += 10 + (c - 'a');
} else {
result += 10 + (c - 'A');
}
}
DWORD r = result & 0x00FF0000;
DWORD g = result & 0x0000FF00;
DWORD b = result & 0x000000FF;
r = r >> 16;
b = b << 16;
result = r | g | b;
return result;
}
static nsString ToHexString(BYTE n)
{
nsString result;
if (n <= 0x0F) {
result.Append('0');
}
result.AppendInt(n, 16);
return result;
}
static void
BGRIntToRGBString(DWORD color, nsAString& aResult)
{
BYTE r = GetRValue(color);
BYTE g = GetGValue(color);
BYTE b = GetBValue(color);
aResult.Assign('#');
aResult.Append(ToHexString(r));
aResult.Append(ToHexString(g));
aResult.Append(ToHexString(b));
}
} // namespace
static AsyncColorChooser* gColorChooser;
AsyncColorChooser::AsyncColorChooser(COLORREF aInitialColor,
nsIWidget* aParentWidget,
nsIColorPickerShownCallback* aCallback)
: mInitialColor(aInitialColor)
, mColor(aInitialColor)
, mParentWidget(aParentWidget)
, mCallback(aCallback)
{
}
NS_IMETHODIMP
AsyncColorChooser::Run()
{
static COLORREF sCustomColors[16] = {0} ;
MOZ_ASSERT(NS_IsMainThread(),
"Color pickers can only be opened from main thread currently");
// Allow only one color picker to be opened at a time, to workaround bug 944737
if (!gColorChooser) {
mozilla::AutoRestore<AsyncColorChooser*> restoreColorChooser(gColorChooser);
gColorChooser = this;
AutoDestroyTmpWindow adtw((HWND) (mParentWidget.get() ?
mParentWidget->GetNativeData(NS_NATIVE_TMP_WINDOW) : nullptr));
CHOOSECOLOR options;
options.lStructSize = sizeof(options);
options.hwndOwner = adtw.get();
options.Flags = CC_RGBINIT | CC_FULLOPEN | CC_ENABLEHOOK;
options.rgbResult = mInitialColor;
options.lpCustColors = sCustomColors;
options.lpfnHook = HookProc;
mColor = ChooseColor(&options) ? options.rgbResult : mInitialColor;
} else {
NS_WARNING("Currently, it's not possible to open more than one color "
"picker at a time");
mColor = mInitialColor;
}
if (mCallback) {
nsAutoString colorStr;
BGRIntToRGBString(mColor, colorStr);
mCallback->Done(colorStr);
}
return NS_OK;
}
void
AsyncColorChooser::Update(COLORREF aColor)
{
if (mColor != aColor) {
mColor = aColor;
nsAutoString colorStr;
BGRIntToRGBString(mColor, colorStr);
mCallback->Update(colorStr);
}
}
/* static */ UINT_PTR CALLBACK
AsyncColorChooser::HookProc(HWND aDialog, UINT aMsg,
WPARAM aWParam, LPARAM aLParam)
{
if (!gColorChooser) {
return 0;
}
if (aMsg == WM_CTLCOLORSTATIC) {
// The color picker does not expose a proper way to retrieve the current
// color, so we need to obtain it from the static control displaying the
// current color instead.
const int kCurrentColorBoxID = 709;
if ((HWND)aLParam == GetDlgItem(aDialog, kCurrentColorBoxID)) {
gColorChooser->Update(GetPixel((HDC)aWParam, 0, 0));
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// nsIColorPicker
nsColorPicker::nsColorPicker()
{
}
nsColorPicker::~nsColorPicker()
{
}
NS_IMPL_ISUPPORTS(nsColorPicker, nsIColorPicker)
NS_IMETHODIMP
nsColorPicker::Init(mozIDOMWindowProxy* parent,
const nsAString& title,
const nsAString& aInitialColor)
{
NS_PRECONDITION(parent,
"Null parent passed to colorpicker, no color picker for you!");
mParentWidget = WidgetUtils::DOMWindowToWidget(nsPIDOMWindowOuter::From(parent));
mInitialColor = ColorStringToRGB(aInitialColor);
return NS_OK;
}
NS_IMETHODIMP
nsColorPicker::Open(nsIColorPickerShownCallback* aCallback)
{
NS_ENSURE_ARG(aCallback);
nsCOMPtr<nsIRunnable> event = new AsyncColorChooser(mInitialColor,
mParentWidget,
aCallback);
return NS_DispatchToMainThread(event);
}

View file

@ -0,0 +1,59 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsColorPicker_h__
#define nsColorPicker_h__
#include <windows.h>
#include <commdlg.h>
#include "nsCOMPtr.h"
#include "nsIColorPicker.h"
#include "nsThreadUtils.h"
class nsIWidget;
class AsyncColorChooser :
public mozilla::Runnable
{
public:
AsyncColorChooser(COLORREF aInitialColor,
nsIWidget* aParentWidget,
nsIColorPickerShownCallback* aCallback);
NS_IMETHOD Run() override;
private:
void Update(COLORREF aColor);
static UINT_PTR CALLBACK HookProc(HWND aDialog, UINT aMsg,
WPARAM aWParam, LPARAM aLParam);
COLORREF mInitialColor;
COLORREF mColor;
nsCOMPtr<nsIWidget> mParentWidget;
nsCOMPtr<nsIColorPickerShownCallback> mCallback;
};
class nsColorPicker :
public nsIColorPicker
{
virtual ~nsColorPicker();
public:
nsColorPicker();
NS_DECL_ISUPPORTS
NS_IMETHOD Init(mozIDOMWindowProxy* parent, const nsAString& title,
const nsAString& aInitialColor);
NS_IMETHOD Open(nsIColorPickerShownCallback* aCallback);
private:
COLORREF mInitialColor;
nsCOMPtr<nsIWidget> mParentWidget;
};
#endif // nsColorPicker_h__

2166
widget/windows/nsDataObj.cpp Normal file

File diff suppressed because it is too large Load diff

296
widget/windows/nsDataObj.h Normal file
View file

@ -0,0 +1,296 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _NSDATAOBJ_H_
#define _NSDATAOBJ_H_
#include <oleidl.h>
#include <shldisp.h>
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsIFile.h"
#include "nsIURI.h"
#include "nsIInputStream.h"
#include "nsIStreamListener.h"
#include "nsIChannel.h"
#include "nsCOMArray.h"
#include "nsITimer.h"
class nsIThread;
class nsIPrincipal;
// The SDK shipping with VC11 has renamed IAsyncOperation to
// IDataObjectAsyncCapability. We try to detect this, and rename this in our
// code too to make sure that we pick the correct name when building.
#ifdef __IDataObjectAsyncCapability_INTERFACE_DEFINED__
#define IAsyncOperation IDataObjectAsyncCapability
#define IID_IAsyncOperation IID_IDataObjectAsyncCapability
#else
// XXX for older version of PSDK where IAsyncOperation and related stuff is not available
// but thisdefine should be removed when parocles config is updated
#ifndef __IAsyncOperation_INTERFACE_DEFINED__
// IAsyncOperation interface definition
EXTERN_C const IID IID_IAsyncOperation;
MIDL_INTERFACE("3D8B0590-F691-11d2-8EA9-006097DF5BD4")
IAsyncOperation : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE SetAsyncMode(BOOL fDoOpAsync) = 0;
virtual HRESULT STDMETHODCALLTYPE GetAsyncMode(BOOL *pfIsOpAsync) = 0;
virtual HRESULT STDMETHODCALLTYPE StartOperation(IBindCtx *pbcReserved) = 0;
virtual HRESULT STDMETHODCALLTYPE InOperation(BOOL *pfInAsyncOp) = 0;
virtual HRESULT STDMETHODCALLTYPE EndOperation(HRESULT hResult,
IBindCtx *pbcReserved,
DWORD dwEffects) = 0;
};
// this is not defined in the old headers for some reason
#ifndef FD_PROGRESSUI
#define FD_PROGRESSUI 0x4000
#endif
#endif // __IAsyncOperation_INTERFACE_DEFINED__
#endif // __IDataObjectAsyncCapability_INTERFACE_DEFINED__
/*
* CFSTR_SHELLURL is deprecated and doesn't have a Unicode version.
* Therefore we are using CFSTR_INETURL instead of CFSTR_SHELLURL.
* See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_programming/transferring/clipboard.asp
*/
#ifndef CFSTR_INETURLA
#define CFSTR_INETURLA L"UniformResourceLocator"
#endif
#ifndef CFSTR_INETURLW
#define CFSTR_INETURLW L"UniformResourceLocatorW"
#endif
// For support of MinGW w32api v2.4.
// When the next version of w32api is released with shlobj.h rev 1.35
// http://sources.redhat.com/cgi-bin/cvsweb.cgi/src/winsup/w32api/include/shlobj.h?cvsroot=src
// then that can be made the base required version and this code should be removed.
#ifndef CFSTR_FILEDESCRIPTORA
# define CFSTR_FILEDESCRIPTORA L"FileGroupDescriptor"
#endif
#ifndef CFSTR_FILEDESCRIPTORW
# define CFSTR_FILEDESCRIPTORW L"FileGroupDescriptorW"
#endif
class CEnumFormatEtc;
class nsITransferable;
/*
* This ole registered class is used to facilitate drag-drop of objects which
* can be adapted by an object derived from CfDragDrop. The CfDragDrop is
* associated with instances via SetDragDrop().
*/
class nsDataObj : public IDataObject,
public IAsyncOperation
{
protected:
nsCOMPtr<nsIThread> mIOThread;
public: // construction, destruction
nsDataObj(nsIURI *uri = nullptr);
virtual ~nsDataObj();
public: // IUnknown methods - see iunknown.h for documentation
STDMETHODIMP_(ULONG) AddRef ();
STDMETHODIMP QueryInterface(REFIID, void**);
STDMETHODIMP_(ULONG) Release ();
// support for clipboard
virtual void AddDataFlavor(const char* aDataFlavor, LPFORMATETC aFE);
void SetTransferable(nsITransferable * aTransferable);
// Return the registered OLE class ID of this object's CfDataObj.
CLSID GetClassID() const;
public: // IDataObject methods - these are general comments. see CfDragDrop
// for overriding behavior
// Store data in pSTM according to the format specified by pFE, if the
// format is supported (supported formats are specified in CfDragDrop::
// GetFormats) and return NOERROR; otherwise return DATA_E_FORMATETC. It
// is the callers responsibility to free pSTM if NOERROR is returned.
STDMETHODIMP GetData (LPFORMATETC pFE, LPSTGMEDIUM pSTM);
// Similar to GetData except that the caller allocates the structure
// referenced by pSTM.
STDMETHODIMP GetDataHere (LPFORMATETC pFE, LPSTGMEDIUM pSTM);
// Returns S_TRUE if this object supports the format specified by pSTM,
// S_FALSE otherwise.
STDMETHODIMP QueryGetData (LPFORMATETC pFE);
// Set pCanonFE to the canonical format of pFE if one exists and return
// NOERROR, otherwise return DATA_S_SAMEFORMATETC. A canonical format
// implies an identical rendering.
STDMETHODIMP GetCanonicalFormatEtc (LPFORMATETC pFE, LPFORMATETC pCanonFE);
// Set this objects data according to the format specified by pFE and
// the storage medium specified by pSTM and return NOERROR, if the format
// is supported. If release is TRUE this object must release the storage
// associated with pSTM.
STDMETHODIMP SetData (LPFORMATETC pFE, LPSTGMEDIUM pSTM, BOOL release);
// Set ppEnum to an IEnumFORMATETC object which will iterate all of the
// data formats that this object supports. direction is either DATADIR_GET
// or DATADIR_SET.
STDMETHODIMP EnumFormatEtc (DWORD direction, LPENUMFORMATETC* ppEnum);
// Set up an advisory connection to this object based on the format specified
// by pFE, flags, and the pAdvise. Set pConn to the established advise
// connection.
STDMETHODIMP DAdvise (LPFORMATETC pFE, DWORD flags, LPADVISESINK pAdvise,
DWORD* pConn);
// Turn off advising of a previous call to DAdvise which set pConn.
STDMETHODIMP DUnadvise (DWORD pConn);
// Set ppEnum to an IEnumSTATDATA object which will iterate over the
// existing objects which have established advisory connections to this
// object.
STDMETHODIMP EnumDAdvise (LPENUMSTATDATA *ppEnum);
// IAsyncOperation methods
STDMETHOD(EndOperation)(HRESULT hResult, IBindCtx *pbcReserved, DWORD dwEffects);
STDMETHOD(GetAsyncMode)(BOOL *pfIsOpAsync);
STDMETHOD(InOperation)(BOOL *pfInAsyncOp);
STDMETHOD(SetAsyncMode)(BOOL fDoOpAsync);
STDMETHOD(StartOperation)(IBindCtx *pbcReserved);
public: // other methods
// Gets the filename from the kFilePromiseURLMime flavour
HRESULT GetDownloadDetails(nsIURI **aSourceURI,
nsAString &aFilename);
protected:
// help determine the kind of drag
bool IsFlavourPresent(const char *inFlavour);
virtual HRESULT AddSetFormat(FORMATETC& FE);
virtual HRESULT AddGetFormat(FORMATETC& FE);
virtual HRESULT GetFile ( FORMATETC& aFE, STGMEDIUM& aSTG );
virtual HRESULT GetText ( const nsACString& aDF, FORMATETC& aFE, STGMEDIUM & aSTG );
virtual HRESULT GetDib ( const nsACString& inFlavor, FORMATETC &, STGMEDIUM & aSTG );
virtual HRESULT GetMetafilePict(FORMATETC& FE, STGMEDIUM& STM);
virtual HRESULT DropImage( FORMATETC& aFE, STGMEDIUM& aSTG );
virtual HRESULT DropFile( FORMATETC& aFE, STGMEDIUM& aSTG );
virtual HRESULT DropTempFile( FORMATETC& aFE, STGMEDIUM& aSTG );
virtual HRESULT GetUniformResourceLocator ( FORMATETC& aFE, STGMEDIUM& aSTG, bool aIsUnicode ) ;
virtual HRESULT ExtractUniformResourceLocatorA ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
virtual HRESULT ExtractUniformResourceLocatorW ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
virtual HRESULT GetFileDescriptor ( FORMATETC& aFE, STGMEDIUM& aSTG, bool aIsUnicode ) ;
virtual HRESULT GetFileContents ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
virtual HRESULT GetPreferredDropEffect ( FORMATETC& aFE, STGMEDIUM& aSTG );
virtual HRESULT SetBitmap(FORMATETC& FE, STGMEDIUM& STM);
virtual HRESULT SetDib (FORMATETC& FE, STGMEDIUM& STM);
virtual HRESULT SetText (FORMATETC& FE, STGMEDIUM& STM);
virtual HRESULT SetMetafilePict(FORMATETC& FE, STGMEDIUM& STM);
// Provide the structures needed for an internet shortcut by the shell
virtual HRESULT GetFileDescriptorInternetShortcutA ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
virtual HRESULT GetFileDescriptorInternetShortcutW ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
virtual HRESULT GetFileContentsInternetShortcut ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
// IStream implementation
virtual HRESULT GetFileDescriptor_IStreamA ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
virtual HRESULT GetFileDescriptor_IStreamW ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
virtual HRESULT GetFileContents_IStream ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
nsresult ExtractShortcutURL ( nsString & outURL ) ;
nsresult ExtractShortcutTitle ( nsString & outTitle ) ;
// munge our HTML data to win32's CF_HTML spec. Will null terminate
nsresult BuildPlatformHTML ( const char* inOurHTML, char** outPlatformHTML ) ;
// Used for the SourceURL part of CF_HTML
nsCString mSourceURL;
BOOL FormatsMatch(const FORMATETC& source, const FORMATETC& target) const;
ULONG m_cRef; // the reference count
nsTArray<nsCString> mDataFlavors;
nsITransferable * mTransferable; // nsDataObj owns and ref counts nsITransferable,
// the nsITransferable does know anything about the nsDataObj
CEnumFormatEtc * m_enumFE; // Ownership Rules:
// nsDataObj owns and ref counts CEnumFormatEtc,
nsCOMPtr<nsIFile> mCachedTempFile;
BOOL mIsAsyncMode;
BOOL mIsInOperation;
///////////////////////////////////////////////////////////////////////////////
// CStream class implementation
// this class is used in Drag and drop with download sample
// called from IDataObject::GetData
class CStream : public IStream, public nsIStreamListener
{
nsCOMPtr<nsIChannel> mChannel;
FallibleTArray<uint8_t> mChannelData;
bool mChannelRead;
nsresult mChannelResult;
uint32_t mStreamRead;
protected:
virtual ~CStream();
nsresult WaitForCompletion();
public:
CStream();
nsresult Init(nsIURI *pSourceURI,
uint32_t aContentPolicyType,
nsIPrincipal* aRequestingPrincipal);
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
// IUnknown
STDMETHOD(QueryInterface)(REFIID refiid, void** ppvResult);
// IStream
STDMETHOD(Clone)(IStream** ppStream);
STDMETHOD(Commit)(DWORD dwFrags);
STDMETHOD(CopyTo)(IStream* pDestStream, ULARGE_INTEGER nBytesToCopy, ULARGE_INTEGER* nBytesRead, ULARGE_INTEGER* nBytesWritten);
STDMETHOD(LockRegion)(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes, DWORD dwFlags);
STDMETHOD(Read)(void* pvBuffer, ULONG nBytesToRead, ULONG* nBytesRead);
STDMETHOD(Revert)(void);
STDMETHOD(Seek)(LARGE_INTEGER nMove, DWORD dwOrigin, ULARGE_INTEGER* nNewPos);
STDMETHOD(SetSize)(ULARGE_INTEGER nNewSize);
STDMETHOD(Stat)(STATSTG* statstg, DWORD dwFlags);
STDMETHOD(UnlockRegion)(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes, DWORD dwFlags);
STDMETHOD(Write)(const void* pvBuffer, ULONG nBytesToRead, ULONG* nBytesRead);
};
HRESULT CreateStream(IStream **outStream);
private:
// Drag and drop helper data for implementing drag and drop image support
typedef struct {
FORMATETC fe;
STGMEDIUM stgm;
} DATAENTRY, *LPDATAENTRY;
nsTArray <LPDATAENTRY> mDataEntryList;
nsCOMPtr<nsITimer> mTimer;
bool LookupArbitraryFormat(FORMATETC *aFormat, LPDATAENTRY *aDataEntry, BOOL aAddorUpdate);
bool CopyMediumData(STGMEDIUM *aMediumDst, STGMEDIUM *aMediumSrc, LPFORMATETC aFormat, BOOL aSetData);
static void RemoveTempFile(nsITimer* aTimer, void* aClosure);
};
#endif // _NSDATAOBJ_H_

View file

@ -0,0 +1,405 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <shlobj.h>
#include "nsDataObjCollection.h"
#include "nsClipboard.h"
#include "IEnumFE.h"
#include <ole2.h>
// {25589C3E-1FAC-47b9-BF43-CAEA89B79533}
const IID IID_IDataObjCollection =
{0x25589c3e, 0x1fac, 0x47b9, {0xbf, 0x43, 0xca, 0xea, 0x89, 0xb7, 0x95, 0x33}};
/*
* Class nsDataObjCollection
*/
nsDataObjCollection::nsDataObjCollection()
: m_cRef(0)
{
}
nsDataObjCollection::~nsDataObjCollection()
{
mDataObjects.Clear();
}
// IUnknown interface methods - see iunknown.h for documentation
STDMETHODIMP nsDataObjCollection::QueryInterface(REFIID riid, void** ppv)
{
*ppv=nullptr;
if ( (IID_IUnknown == riid) || (IID_IDataObject == riid) ) {
*ppv = static_cast<IDataObject*>(this);
AddRef();
return NOERROR;
}
if ( IID_IDataObjCollection == riid ) {
*ppv = static_cast<nsIDataObjCollection*>(this);
AddRef();
return NOERROR;
}
//offer to operate asynchronously (required by nsDragService)
if (IID_IAsyncOperation == riid) {
*ppv = static_cast<IAsyncOperation*>(this);
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) nsDataObjCollection::AddRef()
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) nsDataObjCollection::Release()
{
if (0 != --m_cRef)
return m_cRef;
delete this;
return 0;
}
// IDataObject methods
STDMETHODIMP nsDataObjCollection::GetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
{
static CLIPFORMAT fileDescriptorFlavorA =
::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA);
static CLIPFORMAT fileDescriptorFlavorW =
::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
static CLIPFORMAT fileFlavor = ::RegisterClipboardFormat(CFSTR_FILECONTENTS);
switch (pFE->cfFormat) {
case CF_TEXT:
case CF_UNICODETEXT:
return GetText(pFE, pSTM);
case CF_HDROP:
return GetFile(pFE, pSTM);
default:
if (pFE->cfFormat == fileDescriptorFlavorA ||
pFE->cfFormat == fileDescriptorFlavorW) {
return GetFileDescriptors(pFE, pSTM);
}
if (pFE->cfFormat == fileFlavor) {
return GetFileContents(pFE, pSTM);
}
}
return GetFirstSupporting(pFE, pSTM);
}
STDMETHODIMP nsDataObjCollection::GetDataHere(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
{
return E_FAIL;
}
// Other objects querying to see if we support a particular format
STDMETHODIMP nsDataObjCollection::QueryGetData(LPFORMATETC pFE)
{
UINT format = nsClipboard::GetFormat(MULTI_MIME);
if (format == pFE->cfFormat) {
return S_OK;
}
for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
IDataObject * dataObj = mDataObjects.ElementAt(i);
if (S_OK == dataObj->QueryGetData(pFE)) {
return S_OK;
}
}
return DV_E_FORMATETC;
}
STDMETHODIMP nsDataObjCollection::SetData(LPFORMATETC pFE,
LPSTGMEDIUM pSTM,
BOOL fRelease)
{
// Set arbitrary data formats on the first object in the collection and let
// it handle the heavy lifting
if (mDataObjects.Length() == 0)
return E_FAIL;
return mDataObjects.ElementAt(0)->SetData(pFE, pSTM, fRelease);
}
// Registers a DataFlavor/FE pair
void nsDataObjCollection::AddDataFlavor(const char * aDataFlavor,
LPFORMATETC aFE)
{
// Add the FormatEtc to our list if it's not already there. We don't care
// about the internal aDataFlavor because nsDataObj handles that.
IEnumFORMATETC * ifEtc;
FORMATETC fEtc;
ULONG num;
if (S_OK != this->EnumFormatEtc(DATADIR_GET, &ifEtc))
return;
while (S_OK == ifEtc->Next(1, &fEtc, &num)) {
NS_ASSERTION(1 == num,
"Bit off more than we can chew in nsDataObjCollection::AddDataFlavor");
if (FormatsMatch(fEtc, *aFE)) {
ifEtc->Release();
return;
}
} // If we didn't find a matching format, add this one
ifEtc->Release();
m_enumFE->AddFormatEtc(aFE);
}
// We accept ownership of the nsDataObj which we free on destruction
void nsDataObjCollection::AddDataObject(IDataObject * aDataObj)
{
nsDataObj* dataObj = reinterpret_cast<nsDataObj*>(aDataObj);
mDataObjects.AppendElement(dataObj);
}
// Methods for getting data
HRESULT nsDataObjCollection::GetFile(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
{
STGMEDIUM workingmedium;
FORMATETC fe = *pFE;
HGLOBAL hGlobalMemory;
HRESULT hr;
// Make enough space for the header and the trailing null
uint32_t buffersize = sizeof(DROPFILES) + sizeof(char16_t);
uint32_t alloclen = 0;
char16_t* realbuffer;
nsAutoString filename;
hGlobalMemory = GlobalAlloc(GHND, buffersize);
for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
nsDataObj* dataObj = mDataObjects.ElementAt(i);
hr = dataObj->GetData(&fe, &workingmedium);
if (hr != S_OK) {
switch (hr) {
case DV_E_FORMATETC:
continue;
default:
return hr;
}
}
// Now we need to pull out the filename
char16_t* buffer = (char16_t*)GlobalLock(workingmedium.hGlobal);
if (buffer == nullptr)
return E_FAIL;
buffer += sizeof(DROPFILES)/sizeof(char16_t);
filename = buffer;
GlobalUnlock(workingmedium.hGlobal);
ReleaseStgMedium(&workingmedium);
// Now put the filename into our buffer
alloclen = (filename.Length() + 1) * sizeof(char16_t);
hGlobalMemory = ::GlobalReAlloc(hGlobalMemory, buffersize + alloclen, GHND);
if (hGlobalMemory == nullptr)
return E_FAIL;
realbuffer = (char16_t*)((char*)GlobalLock(hGlobalMemory) + buffersize);
if (!realbuffer)
return E_FAIL;
realbuffer--; // Overwrite the preceding null
memcpy(realbuffer, filename.get(), alloclen);
GlobalUnlock(hGlobalMemory);
buffersize += alloclen;
}
// We get the last null (on the double null terminator) for free since we used
// the zero memory flag when we allocated. All we need to do is fill the
// DROPFILES structure
DROPFILES* df = (DROPFILES*)GlobalLock(hGlobalMemory);
if (!df)
return E_FAIL;
df->pFiles = sizeof(DROPFILES); //Offset to start of file name string
df->fNC = 0;
df->pt.x = 0;
df->pt.y = 0;
df->fWide = TRUE; // utf-16 chars
GlobalUnlock(hGlobalMemory);
// Finally fill out the STGMEDIUM struct
pSTM->tymed = TYMED_HGLOBAL;
pSTM->pUnkForRelease = nullptr; // Caller gets to free the data
pSTM->hGlobal = hGlobalMemory;
return S_OK;
}
HRESULT nsDataObjCollection::GetText(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
{
STGMEDIUM workingmedium;
FORMATETC fe = *pFE;
HGLOBAL hGlobalMemory;
HRESULT hr;
uint32_t buffersize = 1;
uint32_t alloclen = 0;
hGlobalMemory = GlobalAlloc(GHND, buffersize);
if (pFE->cfFormat == CF_TEXT) {
nsAutoCString text;
for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
nsDataObj* dataObj = mDataObjects.ElementAt(i);
hr = dataObj->GetData(&fe, &workingmedium);
if (hr != S_OK) {
switch (hr) {
case DV_E_FORMATETC:
continue;
default:
return hr;
}
}
// Now we need to pull out the text
char* buffer = (char*)GlobalLock(workingmedium.hGlobal);
if (buffer == nullptr)
return E_FAIL;
text = buffer;
GlobalUnlock(workingmedium.hGlobal);
ReleaseStgMedium(&workingmedium);
// Now put the text into our buffer
alloclen = text.Length();
hGlobalMemory = ::GlobalReAlloc(hGlobalMemory, buffersize + alloclen,
GHND);
if (hGlobalMemory == nullptr)
return E_FAIL;
buffer = ((char*)GlobalLock(hGlobalMemory) + buffersize);
if (!buffer)
return E_FAIL;
buffer--; // Overwrite the preceding null
memcpy(buffer, text.get(), alloclen);
GlobalUnlock(hGlobalMemory);
buffersize += alloclen;
}
pSTM->tymed = TYMED_HGLOBAL;
pSTM->pUnkForRelease = nullptr; // Caller gets to free the data
pSTM->hGlobal = hGlobalMemory;
return S_OK;
}
if (pFE->cfFormat == CF_UNICODETEXT) {
buffersize = sizeof(char16_t);
nsAutoString text;
for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
nsDataObj* dataObj = mDataObjects.ElementAt(i);
hr = dataObj->GetData(&fe, &workingmedium);
if (hr != S_OK) {
switch (hr) {
case DV_E_FORMATETC:
continue;
default:
return hr;
}
}
// Now we need to pull out the text
char16_t* buffer = (char16_t*)GlobalLock(workingmedium.hGlobal);
if (buffer == nullptr)
return E_FAIL;
text = buffer;
GlobalUnlock(workingmedium.hGlobal);
ReleaseStgMedium(&workingmedium);
// Now put the text into our buffer
alloclen = text.Length() * sizeof(char16_t);
hGlobalMemory = ::GlobalReAlloc(hGlobalMemory, buffersize + alloclen,
GHND);
if (hGlobalMemory == nullptr)
return E_FAIL;
buffer = (char16_t*)((char*)GlobalLock(hGlobalMemory) + buffersize);
if (!buffer)
return E_FAIL;
buffer--; // Overwrite the preceding null
memcpy(buffer, text.get(), alloclen);
GlobalUnlock(hGlobalMemory);
buffersize += alloclen;
}
pSTM->tymed = TYMED_HGLOBAL;
pSTM->pUnkForRelease = nullptr; // Caller gets to free the data
pSTM->hGlobal = hGlobalMemory;
return S_OK;
}
return E_FAIL;
}
HRESULT nsDataObjCollection::GetFileDescriptors(LPFORMATETC pFE,
LPSTGMEDIUM pSTM)
{
STGMEDIUM workingmedium;
FORMATETC fe = *pFE;
HGLOBAL hGlobalMemory;
HRESULT hr;
uint32_t buffersize = sizeof(UINT);
uint32_t alloclen = sizeof(FILEDESCRIPTOR);
hGlobalMemory = GlobalAlloc(GHND, buffersize);
for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
nsDataObj* dataObj = mDataObjects.ElementAt(i);
hr = dataObj->GetData(&fe, &workingmedium);
if (hr != S_OK) {
switch (hr) {
case DV_E_FORMATETC:
continue;
default:
return hr;
}
}
// Now we need to pull out the filedescriptor
FILEDESCRIPTOR* buffer =
(FILEDESCRIPTOR*)((char*)GlobalLock(workingmedium.hGlobal) + sizeof(UINT));
if (buffer == nullptr)
return E_FAIL;
hGlobalMemory = ::GlobalReAlloc(hGlobalMemory, buffersize + alloclen, GHND);
if (hGlobalMemory == nullptr)
return E_FAIL;
FILEGROUPDESCRIPTOR* realbuffer =
(FILEGROUPDESCRIPTOR*)GlobalLock(hGlobalMemory);
if (!realbuffer)
return E_FAIL;
FILEDESCRIPTOR* copyloc = (FILEDESCRIPTOR*)((char*)realbuffer + buffersize);
memcpy(copyloc, buffer, alloclen);
realbuffer->cItems++;
GlobalUnlock(hGlobalMemory);
GlobalUnlock(workingmedium.hGlobal);
ReleaseStgMedium(&workingmedium);
buffersize += alloclen;
}
pSTM->tymed = TYMED_HGLOBAL;
pSTM->pUnkForRelease = nullptr; // Caller gets to free the data
pSTM->hGlobal = hGlobalMemory;
return S_OK;
}
HRESULT nsDataObjCollection::GetFileContents(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
{
ULONG num = 0;
ULONG numwanted = (pFE->lindex == -1) ? 0 : pFE->lindex;
FORMATETC fEtc = *pFE;
fEtc.lindex = -1; // We're lying to the data object so it thinks it's alone
// The key for this data type is to figure out which data object the index
// corresponds to and then just pass it along
for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
nsDataObj* dataObj = mDataObjects.ElementAt(i);
if (dataObj->QueryGetData(&fEtc) != S_OK)
continue;
if (num == numwanted)
return dataObj->GetData(pFE, pSTM);
num++;
}
return DV_E_LINDEX;
}
HRESULT nsDataObjCollection::GetFirstSupporting(LPFORMATETC pFE,
LPSTGMEDIUM pSTM)
{
// There is no way to pass more than one of this, so just find the first data
// object that supports it and pass it along
for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
if (mDataObjects.ElementAt(i)->QueryGetData(pFE) == S_OK)
return mDataObjects.ElementAt(i)->GetData(pFE, pSTM);
}
return DV_E_FORMATETC;
}

View file

@ -0,0 +1,95 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _NSDATAOBJCOLLECTION_H_
#define _NSDATAOBJCOLLECTION_H_
#include <oleidl.h>
#include "mozilla/RefPtr.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsDataObj.h"
#include "mozilla/Attributes.h"
#define MULTI_MIME "Mozilla/IDataObjectCollectionFormat"
EXTERN_C const IID IID_IDataObjCollection;
// An interface to make sure we have the right kind of object for D&D
// this way we can filter out collection objects that aren't ours
class nsIDataObjCollection : public IUnknown {
public:
};
/*
* This ole registered class is used to facilitate drag-drop of objects which
* can be adapted by an object derived from CfDragDrop. The CfDragDrop is
* associated with instances via SetDragDrop().
*/
class nsDataObjCollection final : public nsIDataObjCollection, public nsDataObj
{
public:
nsDataObjCollection();
~nsDataObjCollection();
public: // IUnknown methods - see iunknown.h for documentation
STDMETHODIMP_(ULONG) AddRef ();
STDMETHODIMP QueryInterface(REFIID, void**);
STDMETHODIMP_(ULONG) Release ();
public: // DataGet and DataSet helper methods
virtual HRESULT GetFile(LPFORMATETC pFE, LPSTGMEDIUM pSTM);
virtual HRESULT GetText(LPFORMATETC pFE, LPSTGMEDIUM pSTM);
virtual HRESULT GetFileDescriptors(LPFORMATETC pFE, LPSTGMEDIUM pSTM);
virtual HRESULT GetFileContents(LPFORMATETC pFE, LPSTGMEDIUM pSTM);
virtual HRESULT GetFirstSupporting(LPFORMATETC pFE, LPSTGMEDIUM pSTM);
using nsDataObj::GetFile;
using nsDataObj::GetFileContents;
using nsDataObj::GetText;
// support for clipboard
void AddDataFlavor(const char * aDataFlavor, LPFORMATETC aFE);
// from nsPIDataObjCollection
void AddDataObject(IDataObject * aDataObj);
int32_t GetNumDataObjects() { return mDataObjects.Length(); }
nsDataObj* GetDataObjectAt(uint32_t aItem)
{ return mDataObjects.SafeElementAt(aItem, RefPtr<nsDataObj>()); }
// Return the registered OLE class ID of this object's CfDataObj.
CLSID GetClassID() const;
public:
// Store data in pSTM according to the format specified by pFE, if the
// format is supported (supported formats are specified in CfDragDrop::
// GetFormats) and return NOERROR; otherwise return DATA_E_FORMATETC. It
// is the callers responsibility to free pSTM if NOERROR is returned.
STDMETHODIMP GetData (LPFORMATETC pFE, LPSTGMEDIUM pSTM);
// Similar to GetData except that the caller allocates the structure
// referenced by pSTM.
STDMETHODIMP GetDataHere (LPFORMATETC pFE, LPSTGMEDIUM pSTM);
// Returns S_TRUE if this object supports the format specified by pSTM,
// S_FALSE otherwise.
STDMETHODIMP QueryGetData (LPFORMATETC pFE);
// Set this objects data according to the format specified by pFE and
// the storage medium specified by pSTM and return NOERROR, if the format
// is supported. If release is TRUE this object must release the storage
// associated with pSTM.
STDMETHODIMP SetData (LPFORMATETC pFE, LPSTGMEDIUM pSTM, BOOL release);
protected:
ULONG m_cRef; // the reference count
nsTArray<RefPtr<nsDataObj> > mDataObjects;
};
#endif //

View file

@ -0,0 +1,669 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsDeviceContextSpecWin.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/gfx/PrintTargetPDF.h"
#include "mozilla/gfx/PrintTargetWindows.h"
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
#include "mozilla/RefPtr.h"
#include "prmem.h"
#include <winspool.h>
#include "nsIWidget.h"
#include "nsTArray.h"
#include "nsIPrintSettingsWin.h"
#include "nsString.h"
#include "nsIServiceManager.h"
#include "nsReadableUtils.h"
#include "nsStringEnumerator.h"
#include "gfxWindowsSurface.h"
#include "nsIFileStreams.h"
#include "nsIWindowWatcher.h"
#include "nsIDOMWindow.h"
#include "mozilla/Services.h"
#include "nsWindowsHelpers.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/Logging.h"
static mozilla::LazyLogModule kWidgetPrintingLogMod("printing-widget");
#define PR_PL(_p1) MOZ_LOG(kWidgetPrintingLogMod, mozilla::LogLevel::Debug, _p1)
using namespace mozilla;
using namespace mozilla::gfx;
static const wchar_t kDriverName[] = L"WINSPOOL";
//----------------------------------------------------------------------------------
// The printer data is shared between the PrinterEnumerator and the nsDeviceContextSpecWin
// The PrinterEnumerator creates the printer info
// but the nsDeviceContextSpecWin cleans it up
// If it gets created (via the Page Setup Dialog) but the user never prints anything
// then it will never be delete, so this class takes care of that.
class GlobalPrinters {
public:
static GlobalPrinters* GetInstance() { return &mGlobalPrinters; }
~GlobalPrinters() { FreeGlobalPrinters(); }
void FreeGlobalPrinters();
bool PrintersAreAllocated() { return mPrinters != nullptr; }
LPWSTR GetItemFromList(int32_t aInx) { return mPrinters?mPrinters->ElementAt(aInx):nullptr; }
nsresult EnumeratePrinterList();
void GetDefaultPrinterName(nsString& aDefaultPrinterName);
uint32_t GetNumPrinters() { return mPrinters?mPrinters->Length():0; }
protected:
GlobalPrinters() {}
nsresult EnumerateNativePrinters();
void ReallocatePrinters();
static GlobalPrinters mGlobalPrinters;
static nsTArray<LPWSTR>* mPrinters;
};
//---------------
// static members
GlobalPrinters GlobalPrinters::mGlobalPrinters;
nsTArray<LPWSTR>* GlobalPrinters::mPrinters = nullptr;
struct AutoFreeGlobalPrinters
{
~AutoFreeGlobalPrinters() {
GlobalPrinters::GetInstance()->FreeGlobalPrinters();
}
};
//----------------------------------------------------------------------------------
nsDeviceContextSpecWin::nsDeviceContextSpecWin()
{
mDriverName = nullptr;
mDeviceName = nullptr;
mDevMode = nullptr;
}
//----------------------------------------------------------------------------------
NS_IMPL_ISUPPORTS(nsDeviceContextSpecWin, nsIDeviceContextSpec)
nsDeviceContextSpecWin::~nsDeviceContextSpecWin()
{
SetDeviceName(nullptr);
SetDriverName(nullptr);
SetDevMode(nullptr);
nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(mPrintSettings));
if (psWin) {
psWin->SetDeviceName(nullptr);
psWin->SetDriverName(nullptr);
psWin->SetDevMode(nullptr);
}
// Free them, we won't need them for a while
GlobalPrinters::GetInstance()->FreeGlobalPrinters();
}
//------------------------------------------------------------------
// helper
static char16_t * GetDefaultPrinterNameFromGlobalPrinters()
{
nsAutoString printerName;
GlobalPrinters::GetInstance()->GetDefaultPrinterName(printerName);
return ToNewUnicode(printerName);
}
//----------------------------------------------------------------------------------
NS_IMETHODIMP nsDeviceContextSpecWin::Init(nsIWidget* aWidget,
nsIPrintSettings* aPrintSettings,
bool aIsPrintPreview)
{
mPrintSettings = aPrintSettings;
nsresult rv = NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE;
if (aPrintSettings) {
// If we're in the child and printing via the parent or we're printing to
// PDF we only need information from the print settings.
mPrintSettings->GetOutputFormat(&mOutputFormat);
if ((XRE_IsContentProcess() &&
Preferences::GetBool("print.print_via_parent")) ||
mOutputFormat == nsIPrintSettings::kOutputFormatPDF) {
return NS_OK;
}
nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(aPrintSettings));
if (psWin) {
char16_t* deviceName;
char16_t* driverName;
psWin->GetDeviceName(&deviceName); // creates new memory (makes a copy)
psWin->GetDriverName(&driverName); // creates new memory (makes a copy)
LPDEVMODEW devMode;
psWin->GetDevMode(&devMode); // creates new memory (makes a copy)
if (deviceName && driverName && devMode) {
// Scaling is special, it is one of the few
// devMode items that we control in layout
if (devMode->dmFields & DM_SCALE) {
double scale = double(devMode->dmScale) / 100.0f;
if (scale != 1.0) {
aPrintSettings->SetScaling(scale);
devMode->dmScale = 100;
}
}
SetDeviceName(deviceName);
SetDriverName(driverName);
SetDevMode(devMode);
// clean up
free(deviceName);
free(driverName);
return NS_OK;
} else {
PR_PL(("***** nsDeviceContextSpecWin::Init - deviceName/driverName/devMode was NULL!\n"));
if (deviceName) free(deviceName);
if (driverName) free(driverName);
if (devMode) ::HeapFree(::GetProcessHeap(), 0, devMode);
}
}
} else {
PR_PL(("***** nsDeviceContextSpecWin::Init - aPrintSettingswas NULL!\n"));
}
// Get the Printer Name to be used and output format.
char16_t * printerName = nullptr;
if (mPrintSettings) {
mPrintSettings->GetPrinterName(&printerName);
}
// If there is no name then use the default printer
if (!printerName || (printerName && !*printerName)) {
printerName = GetDefaultPrinterNameFromGlobalPrinters();
}
NS_ASSERTION(printerName, "We have to have a printer name");
if (!printerName || !*printerName) return rv;
return GetDataFromPrinter(printerName, mPrintSettings);
}
//----------------------------------------------------------
// Helper Function - Free and reallocate the string
static void CleanAndCopyString(wchar_t*& aStr, const wchar_t* aNewStr)
{
if (aStr != nullptr) {
if (aNewStr != nullptr && wcslen(aStr) > wcslen(aNewStr)) { // reuse it if we can
wcscpy(aStr, aNewStr);
return;
} else {
PR_Free(aStr);
aStr = nullptr;
}
}
if (nullptr != aNewStr) {
aStr = (wchar_t *)PR_Malloc(sizeof(wchar_t)*(wcslen(aNewStr) + 1));
wcscpy(aStr, aNewStr);
}
}
already_AddRefed<PrintTarget> nsDeviceContextSpecWin::MakePrintTarget()
{
NS_ASSERTION(mDevMode, "DevMode can't be NULL here");
if (mOutputFormat == nsIPrintSettings::kOutputFormatPDF) {
nsXPIDLString filename;
mPrintSettings->GetToFileName(getter_Copies(filename));
double width, height;
mPrintSettings->GetEffectivePageSize(&width, &height);
if (width <= 0 || height <= 0) {
return nullptr;
}
// convert twips to points
width /= TWIPS_PER_POINT_FLOAT;
height /= TWIPS_PER_POINT_FLOAT;
nsCOMPtr<nsIFile> file = do_CreateInstance("@mozilla.org/file/local;1");
nsresult rv = file->InitWithPath(filename);
if (NS_FAILED(rv)) {
return nullptr;
}
nsCOMPtr<nsIFileOutputStream> stream = do_CreateInstance("@mozilla.org/network/file-output-stream;1");
rv = stream->Init(file, -1, -1, 0);
if (NS_FAILED(rv)) {
return nullptr;
}
return PrintTargetPDF::CreateOrNull(stream, IntSize::Truncate(width, height));
}
if (mDevMode) {
NS_WARNING_ASSERTION(mDriverName, "No driver!");
HDC dc = ::CreateDCW(mDriverName, mDeviceName, nullptr, mDevMode);
if (!dc) {
gfxCriticalError(gfxCriticalError::DefaultOptions(false))
<< "Failed to create device context in GetSurfaceForPrinter";
return nullptr;
}
// The PrintTargetWindows takes over ownership of this DC
return PrintTargetWindows::CreateOrNull(dc);
}
return nullptr;
}
float
nsDeviceContextSpecWin::GetDPI()
{
// To match the previous printing code we need to return 72 when printing to
// PDF and 144 when printing to a Windows surface.
return mOutputFormat == nsIPrintSettings::kOutputFormatPDF ? 72.0f : 144.0f;
}
float
nsDeviceContextSpecWin::GetPrintingScale()
{
MOZ_ASSERT(mPrintSettings);
// To match the previous printing code there is no scaling for PDF.
if (mOutputFormat == nsIPrintSettings::kOutputFormatPDF) {
return 1.0f;
}
// The print settings will have the resolution stored from the real device.
int32_t resolution;
mPrintSettings->GetResolution(&resolution);
return float(resolution) / GetDPI();
}
//----------------------------------------------------------------------------------
void nsDeviceContextSpecWin::SetDeviceName(char16ptr_t aDeviceName)
{
CleanAndCopyString(mDeviceName, aDeviceName);
}
//----------------------------------------------------------------------------------
void nsDeviceContextSpecWin::SetDriverName(char16ptr_t aDriverName)
{
CleanAndCopyString(mDriverName, aDriverName);
}
//----------------------------------------------------------------------------------
void nsDeviceContextSpecWin::SetDevMode(LPDEVMODEW aDevMode)
{
if (mDevMode) {
::HeapFree(::GetProcessHeap(), 0, mDevMode);
}
mDevMode = aDevMode;
}
//------------------------------------------------------------------
void
nsDeviceContextSpecWin::GetDevMode(LPDEVMODEW &aDevMode)
{
aDevMode = mDevMode;
}
#define DISPLAY_LAST_ERROR
//----------------------------------------------------------------------------------
// Setup the object's data member with the selected printer's data
nsresult
nsDeviceContextSpecWin::GetDataFromPrinter(char16ptr_t aName, nsIPrintSettings* aPS)
{
nsresult rv = NS_ERROR_FAILURE;
if (!GlobalPrinters::GetInstance()->PrintersAreAllocated()) {
rv = GlobalPrinters::GetInstance()->EnumeratePrinterList();
if (NS_FAILED(rv)) {
PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't enumerate printers!\n"));
DISPLAY_LAST_ERROR
}
NS_ENSURE_SUCCESS(rv, rv);
}
nsHPRINTER hPrinter = nullptr;
wchar_t *name = (wchar_t*)aName; // Windows APIs use non-const name argument
BOOL status = ::OpenPrinterW(name, &hPrinter, nullptr);
if (status) {
nsAutoPrinter autoPrinter(hPrinter);
LPDEVMODEW pDevMode;
// Allocate a buffer of the correct size.
LONG needed = ::DocumentPropertiesW(nullptr, hPrinter, name, nullptr,
nullptr, 0);
if (needed < 0) {
PR_PL(("**** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't get "
"size of DEVMODE using DocumentPropertiesW(pDeviceName = \"%s\"). "
"GetLastEror() = %08x\n",
aName ? NS_ConvertUTF16toUTF8(aName).get() : "", GetLastError()));
return NS_ERROR_FAILURE;
}
pDevMode = (LPDEVMODEW)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY,
needed);
if (!pDevMode) return NS_ERROR_FAILURE;
// Get the default DevMode for the printer and modify it for our needs.
LONG ret = ::DocumentPropertiesW(nullptr, hPrinter, name,
pDevMode, nullptr, DM_OUT_BUFFER);
if (ret == IDOK && aPS) {
nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aPS);
MOZ_ASSERT(psWin);
psWin->CopyToNative(pDevMode);
// Sets back the changes we made to the DevMode into the Printer Driver
ret = ::DocumentPropertiesW(nullptr, hPrinter, name,
pDevMode, pDevMode,
DM_IN_BUFFER | DM_OUT_BUFFER);
// We need to copy the final DEVMODE settings back to our print settings,
// because they may have been set from invalid prefs.
if (ret == IDOK) {
// We need to get information from the device as well.
nsAutoHDC printerDC(::CreateICW(kDriverName, aName, nullptr, pDevMode));
if (NS_WARN_IF(!printerDC)) {
::HeapFree(::GetProcessHeap(), 0, pDevMode);
return NS_ERROR_FAILURE;
}
psWin->CopyFromNative(printerDC, pDevMode);
}
}
if (ret != IDOK) {
::HeapFree(::GetProcessHeap(), 0, pDevMode);
PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - DocumentProperties call failed code: %d/0x%x\n", ret, ret));
DISPLAY_LAST_ERROR
return NS_ERROR_FAILURE;
}
SetDevMode(pDevMode); // cache the pointer and takes responsibility for the memory
SetDeviceName(aName);
SetDriverName(kDriverName);
rv = NS_OK;
} else {
rv = NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND;
PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't open printer: [%s]\n", NS_ConvertUTF16toUTF8(aName).get()));
DISPLAY_LAST_ERROR
}
return rv;
}
//***********************************************************
// Printer Enumerator
//***********************************************************
nsPrinterEnumeratorWin::nsPrinterEnumeratorWin()
{
}
nsPrinterEnumeratorWin::~nsPrinterEnumeratorWin()
{
// Do not free printers here
// GlobalPrinters::GetInstance()->FreeGlobalPrinters();
}
NS_IMPL_ISUPPORTS(nsPrinterEnumeratorWin, nsIPrinterEnumerator)
//----------------------------------------------------------------------------------
// Return the Default Printer name
NS_IMETHODIMP
nsPrinterEnumeratorWin::GetDefaultPrinterName(char16_t * *aDefaultPrinterName)
{
NS_ENSURE_ARG_POINTER(aDefaultPrinterName);
*aDefaultPrinterName = GetDefaultPrinterNameFromGlobalPrinters(); // helper
return NS_OK;
}
NS_IMETHODIMP
nsPrinterEnumeratorWin::InitPrintSettingsFromPrinter(const char16_t *aPrinterName, nsIPrintSettings *aPrintSettings)
{
NS_ENSURE_ARG_POINTER(aPrinterName);
NS_ENSURE_ARG_POINTER(aPrintSettings);
if (!*aPrinterName) {
return NS_OK;
}
// When printing to PDF on Windows there is no associated printer driver.
int16_t outputFormat;
aPrintSettings->GetOutputFormat(&outputFormat);
if (outputFormat == nsIPrintSettings::kOutputFormatPDF) {
return NS_OK;
}
RefPtr<nsDeviceContextSpecWin> devSpecWin = new nsDeviceContextSpecWin();
if (!devSpecWin) return NS_ERROR_OUT_OF_MEMORY;
if (NS_FAILED(GlobalPrinters::GetInstance()->EnumeratePrinterList())) {
return NS_ERROR_FAILURE;
}
AutoFreeGlobalPrinters autoFreeGlobalPrinters;
// If the settings have already been initialized from prefs then pass these to
// GetDataFromPrinter, so that they are saved to the printer.
bool initializedFromPrefs;
nsresult rv =
aPrintSettings->GetIsInitializedFromPrefs(&initializedFromPrefs);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (initializedFromPrefs) {
// If we pass in print settings to GetDataFromPrinter it already copies
// things back to the settings, so we can return here.
return devSpecWin->GetDataFromPrinter(aPrinterName, aPrintSettings);
}
devSpecWin->GetDataFromPrinter(aPrinterName);
LPDEVMODEW devmode;
devSpecWin->GetDevMode(devmode);
if (NS_WARN_IF(!devmode)) {
return NS_ERROR_FAILURE;
}
aPrintSettings->SetPrinterName(aPrinterName);
// We need to get information from the device as well.
char16ptr_t printerName = aPrinterName;
HDC dc = ::CreateICW(kDriverName, printerName, nullptr, devmode);
if (NS_WARN_IF(!dc)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aPrintSettings);
MOZ_ASSERT(psWin);
psWin->CopyFromNative(dc, devmode);
::DeleteDC(dc);
return NS_OK;
}
//----------------------------------------------------------------------------------
// Enumerate all the Printers from the global array and pass their
// names back (usually to script)
NS_IMETHODIMP
nsPrinterEnumeratorWin::GetPrinterNameList(nsIStringEnumerator **aPrinterNameList)
{
NS_ENSURE_ARG_POINTER(aPrinterNameList);
*aPrinterNameList = nullptr;
nsresult rv = GlobalPrinters::GetInstance()->EnumeratePrinterList();
if (NS_FAILED(rv)) {
PR_PL(("***** nsDeviceContextSpecWin::GetPrinterNameList - Couldn't enumerate printers!\n"));
return rv;
}
uint32_t numPrinters = GlobalPrinters::GetInstance()->GetNumPrinters();
nsTArray<nsString> *printers = new nsTArray<nsString>(numPrinters);
if (!printers)
return NS_ERROR_OUT_OF_MEMORY;
nsString* names = printers->AppendElements(numPrinters);
for (uint32_t printerInx = 0; printerInx < numPrinters; ++printerInx) {
LPWSTR name = GlobalPrinters::GetInstance()->GetItemFromList(printerInx);
names[printerInx].Assign(name);
}
return NS_NewAdoptingStringEnumerator(aPrinterNameList, printers);
}
//----------------------------------------------------------------------------------
//-- Global Printers
//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
// THe array hold the name and port for each printer
void
GlobalPrinters::ReallocatePrinters()
{
if (PrintersAreAllocated()) {
FreeGlobalPrinters();
}
mPrinters = new nsTArray<LPWSTR>();
NS_ASSERTION(mPrinters, "Printers Array is NULL!");
}
//----------------------------------------------------------------------------------
void
GlobalPrinters::FreeGlobalPrinters()
{
if (mPrinters != nullptr) {
for (uint32_t i=0;i<mPrinters->Length();i++) {
free(mPrinters->ElementAt(i));
}
delete mPrinters;
mPrinters = nullptr;
}
}
//----------------------------------------------------------------------------------
nsresult
GlobalPrinters::EnumerateNativePrinters()
{
nsresult rv = NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE;
PR_PL(("-----------------------\n"));
PR_PL(("EnumerateNativePrinters\n"));
WCHAR szDefaultPrinterName[1024];
DWORD status = GetProfileStringW(L"devices", 0, L",",
szDefaultPrinterName,
ArrayLength(szDefaultPrinterName));
if (status > 0) {
DWORD count = 0;
LPWSTR sPtr = szDefaultPrinterName;
LPWSTR ePtr = szDefaultPrinterName + status;
LPWSTR prvPtr = sPtr;
while (sPtr < ePtr) {
if (*sPtr == 0) {
LPWSTR name = wcsdup(prvPtr);
mPrinters->AppendElement(name);
PR_PL(("Printer Name: %s\n", prvPtr));
prvPtr = sPtr+1;
count++;
}
sPtr++;
}
rv = NS_OK;
}
PR_PL(("-----------------------\n"));
return rv;
}
//------------------------------------------------------------------
// Uses the GetProfileString to get the default printer from the registry
void
GlobalPrinters::GetDefaultPrinterName(nsString& aDefaultPrinterName)
{
aDefaultPrinterName.Truncate();
WCHAR szDefaultPrinterName[1024];
DWORD status = GetProfileStringW(L"windows", L"device", 0,
szDefaultPrinterName,
ArrayLength(szDefaultPrinterName));
if (status > 0) {
WCHAR comma = ',';
LPWSTR sPtr = szDefaultPrinterName;
while (*sPtr != comma && *sPtr != 0)
sPtr++;
if (*sPtr == comma) {
*sPtr = 0;
}
aDefaultPrinterName = szDefaultPrinterName;
} else {
aDefaultPrinterName = EmptyString();
}
PR_PL(("DEFAULT PRINTER [%s]\n", aDefaultPrinterName.get()));
}
//----------------------------------------------------------------------------------
// This goes and gets the list of available printers and puts
// the default printer at the beginning of the list
nsresult
GlobalPrinters::EnumeratePrinterList()
{
// reallocate and get a new list each time it is asked for
// this deletes the list and re-allocates them
ReallocatePrinters();
// any of these could only fail with an OUT_MEMORY_ERROR
// PRINTER_ENUM_LOCAL should get the network printers on Win95
nsresult rv = EnumerateNativePrinters();
if (NS_FAILED(rv)) return rv;
// get the name of the default printer
nsAutoString defPrinterName;
GetDefaultPrinterName(defPrinterName);
// put the default printer at the beginning of list
if (!defPrinterName.IsEmpty()) {
for (uint32_t i=0;i<mPrinters->Length();i++) {
LPWSTR name = mPrinters->ElementAt(i);
if (defPrinterName.Equals(name)) {
if (i > 0) {
LPWSTR ptr = mPrinters->ElementAt(0);
mPrinters->ElementAt(0) = name;
mPrinters->ElementAt(i) = ptr;
}
break;
}
}
}
// make sure we at least tried to get the printers
if (!PrintersAreAllocated()) {
PR_PL(("***** nsDeviceContextSpecWin::EnumeratePrinterList - Printers aren`t allocated\n"));
return NS_ERROR_FAILURE;
}
return NS_OK;
}

View file

@ -0,0 +1,84 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsDeviceContextSpecWin_h___
#define nsDeviceContextSpecWin_h___
#include "nsCOMPtr.h"
#include "nsIDeviceContextSpec.h"
#include "nsIPrinterEnumerator.h"
#include "nsIPrintSettings.h"
#include "nsISupportsPrimitives.h"
#include <windows.h>
#include "mozilla/Attributes.h"
#include "mozilla/RefPtr.h"
class nsIWidget;
class nsDeviceContextSpecWin : public nsIDeviceContextSpec
{
public:
nsDeviceContextSpecWin();
NS_DECL_ISUPPORTS
virtual already_AddRefed<PrintTarget> MakePrintTarget() final;
NS_IMETHOD BeginDocument(const nsAString& aTitle,
const nsAString& aPrintToFileName,
int32_t aStartPage,
int32_t aEndPage) override { return NS_OK; }
NS_IMETHOD EndDocument() override { return NS_OK; }
NS_IMETHOD BeginPage() override { return NS_OK; }
NS_IMETHOD EndPage() override { return NS_OK; }
NS_IMETHOD Init(nsIWidget* aWidget, nsIPrintSettings* aPS, bool aIsPrintPreview) override;
float GetDPI() final;
float GetPrintingScale() final;
void GetDriverName(wchar_t *&aDriverName) const { aDriverName = mDriverName; }
void GetDeviceName(wchar_t *&aDeviceName) const { aDeviceName = mDeviceName; }
// The GetDevMode will return a pointer to a DevMode
// whether it is from the Global memory handle or just the DevMode
// To get the DevMode from the Global memory Handle it must lock it
// So this call must be paired with a call to UnlockGlobalHandle
void GetDevMode(LPDEVMODEW &aDevMode);
// helper functions
nsresult GetDataFromPrinter(char16ptr_t aName, nsIPrintSettings* aPS = nullptr);
protected:
void SetDeviceName(char16ptr_t aDeviceName);
void SetDriverName(char16ptr_t aDriverName);
void SetDevMode(LPDEVMODEW aDevMode);
virtual ~nsDeviceContextSpecWin();
wchar_t* mDriverName;
wchar_t* mDeviceName;
LPDEVMODEW mDevMode;
nsCOMPtr<nsIPrintSettings> mPrintSettings;
int16_t mOutputFormat = nsIPrintSettings::kOutputFormatNative;
};
//-------------------------------------------------------------------------
// Printer Enumerator
//-------------------------------------------------------------------------
class nsPrinterEnumeratorWin final : public nsIPrinterEnumerator
{
~nsPrinterEnumeratorWin();
public:
nsPrinterEnumeratorWin();
NS_DECL_ISUPPORTS
NS_DECL_NSIPRINTERENUMERATOR
};
#endif

View file

@ -0,0 +1,641 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <ole2.h>
#include <oleidl.h>
#include <shlobj.h>
#include <shlwapi.h>
// shellapi.h is needed to build with WIN32_LEAN_AND_MEAN
#include <shellapi.h>
#include "mozilla/RefPtr.h"
#include "nsDragService.h"
#include "nsITransferable.h"
#include "nsDataObj.h"
#include "nsWidgetsCID.h"
#include "nsNativeDragTarget.h"
#include "nsNativeDragSource.h"
#include "nsClipboard.h"
#include "nsIDocument.h"
#include "nsDataObjCollection.h"
#include "nsArrayUtils.h"
#include "nsString.h"
#include "nsEscape.h"
#include "nsIScreenManager.h"
#include "nsISupportsPrimitives.h"
#include "nsIURL.h"
#include "nsCWebBrowserPersist.h"
#include "nsToolkit.h"
#include "nsCRT.h"
#include "nsDirectoryServiceDefs.h"
#include "nsUnicharUtils.h"
#include "gfxContext.h"
#include "nsRect.h"
#include "nsMathUtils.h"
#include "WinUtils.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/DataSurfaceHelpers.h"
#include "mozilla/gfx/Tools.h"
using namespace mozilla;
using namespace mozilla::gfx;
//-------------------------------------------------------------------------
//
// DragService constructor
//
//-------------------------------------------------------------------------
nsDragService::nsDragService()
: mDataObject(nullptr), mSentLocalDropEvent(false)
{
}
//-------------------------------------------------------------------------
//
// DragService destructor
//
//-------------------------------------------------------------------------
nsDragService::~nsDragService()
{
NS_IF_RELEASE(mDataObject);
}
bool
nsDragService::CreateDragImage(nsIDOMNode *aDOMNode,
nsIScriptableRegion *aRegion,
SHDRAGIMAGE *psdi)
{
if (!psdi)
return false;
memset(psdi, 0, sizeof(SHDRAGIMAGE));
if (!aDOMNode)
return false;
// Prepare the drag image
LayoutDeviceIntRect dragRect;
RefPtr<SourceSurface> surface;
nsPresContext* pc;
DrawDrag(aDOMNode, aRegion, mScreenPosition, &dragRect, &surface, &pc);
if (!surface)
return false;
uint32_t bmWidth = dragRect.width, bmHeight = dragRect.height;
if (bmWidth == 0 || bmHeight == 0)
return false;
psdi->crColorKey = CLR_NONE;
RefPtr<DataSourceSurface> dataSurface =
Factory::CreateDataSourceSurface(IntSize(bmWidth, bmHeight),
SurfaceFormat::B8G8R8A8);
NS_ENSURE_TRUE(dataSurface, false);
DataSourceSurface::MappedSurface map;
if (!dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) {
return false;
}
RefPtr<DrawTarget> dt =
Factory::CreateDrawTargetForData(BackendType::CAIRO,
map.mData,
dataSurface->GetSize(),
map.mStride,
dataSurface->GetFormat());
if (!dt) {
dataSurface->Unmap();
return false;
}
dt->DrawSurface(surface,
Rect(0, 0, dataSurface->GetSize().width, dataSurface->GetSize().height),
Rect(0, 0, surface->GetSize().width, surface->GetSize().height),
DrawSurfaceOptions(),
DrawOptions(1.0f, CompositionOp::OP_SOURCE));
dt->Flush();
BITMAPV5HEADER bmih;
memset((void*)&bmih, 0, sizeof(BITMAPV5HEADER));
bmih.bV5Size = sizeof(BITMAPV5HEADER);
bmih.bV5Width = bmWidth;
bmih.bV5Height = -(int32_t)bmHeight; // flip vertical
bmih.bV5Planes = 1;
bmih.bV5BitCount = 32;
bmih.bV5Compression = BI_BITFIELDS;
bmih.bV5RedMask = 0x00FF0000;
bmih.bV5GreenMask = 0x0000FF00;
bmih.bV5BlueMask = 0x000000FF;
bmih.bV5AlphaMask = 0xFF000000;
HDC hdcSrc = CreateCompatibleDC(nullptr);
void *lpBits = nullptr;
if (hdcSrc) {
psdi->hbmpDragImage =
::CreateDIBSection(hdcSrc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS,
(void**)&lpBits, nullptr, 0);
if (psdi->hbmpDragImage && lpBits) {
CopySurfaceDataToPackedArray(map.mData, static_cast<uint8_t*>(lpBits),
dataSurface->GetSize(), map.mStride,
BytesPerPixel(dataSurface->GetFormat()));
}
psdi->sizeDragImage.cx = bmWidth;
psdi->sizeDragImage.cy = bmHeight;
LayoutDeviceIntPoint screenPoint =
ConvertToUnscaledDevPixels(pc, mScreenPosition);
psdi->ptOffset.x = screenPoint.x - dragRect.x;
psdi->ptOffset.y = screenPoint.y - dragRect.y;
DeleteDC(hdcSrc);
}
dataSurface->Unmap();
return psdi->hbmpDragImage != nullptr;
}
//-------------------------------------------------------------------------
nsresult
nsDragService::InvokeDragSessionImpl(nsIArray* anArrayTransferables,
nsIScriptableRegion* aRegion,
uint32_t aActionType)
{
// Try and get source URI of the items that are being dragged
nsIURI *uri = nullptr;
nsCOMPtr<nsIDocument> doc(do_QueryInterface(mSourceDocument));
if (doc) {
uri = doc->GetDocumentURI();
}
uint32_t numItemsToDrag = 0;
nsresult rv = anArrayTransferables->GetLength(&numItemsToDrag);
if (!numItemsToDrag)
return NS_ERROR_FAILURE;
// The clipboard class contains some static utility methods that we
// can use to create an IDataObject from the transferable
// if we're dragging more than one item, we need to create a
// "collection" object to fake out the OS. This collection contains
// one |IDataObject| for each transferable. If there is just the one
// (most cases), only pass around the native |IDataObject|.
RefPtr<IDataObject> itemToDrag;
if (numItemsToDrag > 1) {
nsDataObjCollection * dataObjCollection = new nsDataObjCollection();
if (!dataObjCollection)
return NS_ERROR_OUT_OF_MEMORY;
itemToDrag = dataObjCollection;
for (uint32_t i=0; i<numItemsToDrag; ++i) {
nsCOMPtr<nsITransferable> trans =
do_QueryElementAt(anArrayTransferables, i);
if (trans) {
// set the requestingPrincipal on the transferable
nsCOMPtr<nsINode> node = do_QueryInterface(mSourceNode);
trans->SetRequestingPrincipal(node->NodePrincipal());
trans->SetContentPolicyType(mContentPolicyType);
RefPtr<IDataObject> dataObj;
rv = nsClipboard::CreateNativeDataObject(trans,
getter_AddRefs(dataObj), uri);
NS_ENSURE_SUCCESS(rv, rv);
// Add the flavors to the collection object too
rv = nsClipboard::SetupNativeDataObject(trans, dataObjCollection);
NS_ENSURE_SUCCESS(rv, rv);
dataObjCollection->AddDataObject(dataObj);
}
}
} // if dragging multiple items
else {
nsCOMPtr<nsITransferable> trans =
do_QueryElementAt(anArrayTransferables, 0);
if (trans) {
// set the requestingPrincipal on the transferable
nsCOMPtr<nsINode> node = do_QueryInterface(mSourceNode);
trans->SetRequestingPrincipal(node->NodePrincipal());
trans->SetContentPolicyType(mContentPolicyType);
rv = nsClipboard::CreateNativeDataObject(trans,
getter_AddRefs(itemToDrag),
uri);
NS_ENSURE_SUCCESS(rv, rv);
}
} // else dragging a single object
// Create a drag image if support is available
IDragSourceHelper *pdsh;
if (SUCCEEDED(CoCreateInstance(CLSID_DragDropHelper, nullptr,
CLSCTX_INPROC_SERVER,
IID_IDragSourceHelper, (void**)&pdsh))) {
SHDRAGIMAGE sdi;
if (CreateDragImage(mSourceNode, aRegion, &sdi)) {
if (FAILED(pdsh->InitializeFromBitmap(&sdi, itemToDrag)))
DeleteObject(sdi.hbmpDragImage);
}
pdsh->Release();
}
// Kick off the native drag session
return StartInvokingDragSession(itemToDrag, aActionType);
}
static bool
LayoutDevicePointToCSSPoint(const LayoutDevicePoint& aDevPos,
CSSPoint& aCSSPos)
{
nsCOMPtr<nsIScreenManager> screenMgr =
do_GetService("@mozilla.org/gfx/screenmanager;1");
if (!screenMgr) {
return false;
}
nsCOMPtr<nsIScreen> screen;
screenMgr->ScreenForRect(NSToIntRound(aDevPos.x), NSToIntRound(aDevPos.y),
1, 1, getter_AddRefs(screen));
if (!screen) {
return false;
}
int32_t w,h; // unused
LayoutDeviceIntPoint screenOriginDev;
screen->GetRect(&screenOriginDev.x, &screenOriginDev.y, &w, &h);
double scale;
screen->GetDefaultCSSScaleFactor(&scale);
LayoutDeviceToCSSScale devToCSSScale =
CSSToLayoutDeviceScale(scale).Inverse();
// Desktop pixels and CSS pixels share the same screen origin.
CSSIntPoint screenOriginCSS;
screen->GetRectDisplayPix(&screenOriginCSS.x, &screenOriginCSS.y, &w, &h);
aCSSPos = (aDevPos - screenOriginDev) * devToCSSScale + screenOriginCSS;
return true;
}
//-------------------------------------------------------------------------
NS_IMETHODIMP
nsDragService::StartInvokingDragSession(IDataObject * aDataObj,
uint32_t aActionType)
{
// To do the drag we need to create an object that
// implements the IDataObject interface (for OLE)
RefPtr<nsNativeDragSource> nativeDragSrc =
new nsNativeDragSource(mDataTransfer);
// Now figure out what the native drag effect should be
DWORD winDropRes;
DWORD effects = DROPEFFECT_SCROLL;
if (aActionType & DRAGDROP_ACTION_COPY) {
effects |= DROPEFFECT_COPY;
}
if (aActionType & DRAGDROP_ACTION_MOVE) {
effects |= DROPEFFECT_MOVE;
}
if (aActionType & DRAGDROP_ACTION_LINK) {
effects |= DROPEFFECT_LINK;
}
// XXX not sure why we bother to cache this, it can change during
// the drag
mDragAction = aActionType;
mSentLocalDropEvent = false;
// Start dragging
StartDragSession();
OpenDragPopup();
RefPtr<IAsyncOperation> pAsyncOp;
// Offer to do an async drag
if (SUCCEEDED(aDataObj->QueryInterface(IID_IAsyncOperation,
getter_AddRefs(pAsyncOp)))) {
pAsyncOp->SetAsyncMode(VARIANT_TRUE);
} else {
NS_NOTREACHED("When did our data object stop being async");
}
// Call the native D&D method
HRESULT res = ::DoDragDrop(aDataObj, nativeDragSrc, effects, &winDropRes);
// In cases where the drop operation completed outside the application, update
// the source node's nsIDOMDataTransfer dropEffect value so it is up to date.
if (!mSentLocalDropEvent) {
uint32_t dropResult;
// Order is important, since multiple flags can be returned.
if (winDropRes & DROPEFFECT_COPY)
dropResult = DRAGDROP_ACTION_COPY;
else if (winDropRes & DROPEFFECT_LINK)
dropResult = DRAGDROP_ACTION_LINK;
else if (winDropRes & DROPEFFECT_MOVE)
dropResult = DRAGDROP_ACTION_MOVE;
else
dropResult = DRAGDROP_ACTION_NONE;
if (mDataTransfer) {
if (res == DRAGDROP_S_DROP) // Success
mDataTransfer->SetDropEffectInt(dropResult);
else
mDataTransfer->SetDropEffectInt(DRAGDROP_ACTION_NONE);
}
}
mUserCancelled = nativeDragSrc->UserCancelled();
// We're done dragging, get the cursor position and end the drag
// Use GetMessagePos to get the position of the mouse at the last message
// seen by the event loop. (Bug 489729)
// Note that we must convert this from device pixels back to Windows logical
// pixels (bug 818927).
DWORD pos = ::GetMessagePos();
CSSPoint cssPos;
if (!LayoutDevicePointToCSSPoint(LayoutDevicePoint(GET_X_LPARAM(pos),
GET_Y_LPARAM(pos)),
cssPos)) {
// fallback to the simple scaling
POINT pt = { GET_X_LPARAM(pos), GET_Y_LPARAM(pos) };
HMONITOR monitor = ::MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
double dpiScale = widget::WinUtils::LogToPhysFactor(monitor);
cssPos.x = GET_X_LPARAM(pos) / dpiScale;
cssPos.y = GET_Y_LPARAM(pos) / dpiScale;
}
// We have to abuse SetDragEndPoint to pass CSS pixels because
// Event::GetScreenCoords will not convert pixels for dragend events
// until bug 1224754 is fixed.
SetDragEndPoint(LayoutDeviceIntPoint(NSToIntRound(cssPos.x),
NSToIntRound(cssPos.y)));
EndDragSession(true);
mDoingDrag = false;
return DRAGDROP_S_DROP == res ? NS_OK : NS_ERROR_FAILURE;
}
//-------------------------------------------------------------------------
// Make Sure we have the right kind of object
nsDataObjCollection*
nsDragService::GetDataObjCollection(IDataObject* aDataObj)
{
nsDataObjCollection * dataObjCol = nullptr;
if (aDataObj) {
nsIDataObjCollection* dataObj;
if (aDataObj->QueryInterface(IID_IDataObjCollection,
(void**)&dataObj) == S_OK) {
dataObjCol = static_cast<nsDataObjCollection*>(aDataObj);
dataObj->Release();
}
}
return dataObjCol;
}
//-------------------------------------------------------------------------
NS_IMETHODIMP
nsDragService::GetNumDropItems(uint32_t * aNumItems)
{
if (!mDataObject) {
*aNumItems = 0;
return NS_OK;
}
if (IsCollectionObject(mDataObject)) {
nsDataObjCollection * dataObjCol = GetDataObjCollection(mDataObject);
if (dataObjCol) {
*aNumItems = dataObjCol->GetNumDataObjects();
}
else {
// If the count cannot be determined just return 0.
// This can happen if we have collection data of type
// MULTI_MIME ("Mozilla/IDataObjectCollectionFormat") on the clipboard
// from another process but we can't obtain an IID_IDataObjCollection
// from this process.
*aNumItems = 0;
}
}
else {
// Next check if we have a file drop. Return the number of files in
// the file drop as the number of items we have, pretending like we
// actually have > 1 drag item.
FORMATETC fe2;
SET_FORMATETC(fe2, CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
if (mDataObject->QueryGetData(&fe2) == S_OK) {
STGMEDIUM stm;
if (mDataObject->GetData(&fe2, &stm) == S_OK) {
HDROP hdrop = (HDROP)GlobalLock(stm.hGlobal);
*aNumItems = ::DragQueryFileW(hdrop, 0xFFFFFFFF, nullptr, 0);
::GlobalUnlock(stm.hGlobal);
::ReleaseStgMedium(&stm);
// Data may be provided later, so assume we have 1 item
if (*aNumItems == 0)
*aNumItems = 1;
}
else
*aNumItems = 1;
}
else
*aNumItems = 1;
}
return NS_OK;
}
//-------------------------------------------------------------------------
NS_IMETHODIMP
nsDragService::GetData(nsITransferable * aTransferable, uint32_t anItem)
{
// This typcially happens on a drop, the target would be asking
// for it's transferable to be filled in
// Use a static clipboard utility method for this
if (!mDataObject)
return NS_ERROR_FAILURE;
nsresult dataFound = NS_ERROR_FAILURE;
if (IsCollectionObject(mDataObject)) {
// multiple items, use |anItem| as an index into our collection
nsDataObjCollection * dataObjCol = GetDataObjCollection(mDataObject);
uint32_t cnt = dataObjCol->GetNumDataObjects();
if (anItem < cnt) {
IDataObject * dataObj = dataObjCol->GetDataObjectAt(anItem);
dataFound = nsClipboard::GetDataFromDataObject(dataObj, 0, nullptr,
aTransferable);
}
else
NS_WARNING("Index out of range!");
}
else {
// If they are asking for item "0", we can just get it...
if (anItem == 0) {
dataFound = nsClipboard::GetDataFromDataObject(mDataObject, anItem,
nullptr, aTransferable);
} else {
// It better be a file drop, or else non-zero indexes are invalid!
FORMATETC fe2;
SET_FORMATETC(fe2, CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
if (mDataObject->QueryGetData(&fe2) == S_OK)
dataFound = nsClipboard::GetDataFromDataObject(mDataObject, anItem,
nullptr, aTransferable);
else
NS_WARNING("Reqesting non-zero index, but clipboard data is not a collection!");
}
}
return dataFound;
}
//---------------------------------------------------------
NS_IMETHODIMP
nsDragService::SetIDataObject(IDataObject * aDataObj)
{
// When the native drag starts the DragService gets
// the IDataObject that is being dragged
NS_IF_RELEASE(mDataObject);
mDataObject = aDataObj;
NS_IF_ADDREF(mDataObject);
return NS_OK;
}
//---------------------------------------------------------
void
nsDragService::SetDroppedLocal()
{
// Sent from the native drag handler, letting us know
// a drop occurred within the application vs. outside of it.
mSentLocalDropEvent = true;
return;
}
//-------------------------------------------------------------------------
NS_IMETHODIMP
nsDragService::IsDataFlavorSupported(const char *aDataFlavor, bool *_retval)
{
if (!aDataFlavor || !mDataObject || !_retval)
return NS_ERROR_FAILURE;
#ifdef DEBUG
if (strcmp(aDataFlavor, kTextMime) == 0)
NS_WARNING("DO NOT USE THE text/plain DATA FLAVOR ANY MORE. USE text/unicode INSTEAD");
#endif
*_retval = false;
FORMATETC fe;
UINT format = 0;
if (IsCollectionObject(mDataObject)) {
// We know we have one of our special collection objects.
format = nsClipboard::GetFormat(aDataFlavor);
SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1,
TYMED_HGLOBAL | TYMED_FILE | TYMED_GDI);
// See if any one of the IDataObjects in the collection supports
// this data type
nsDataObjCollection* dataObjCol = GetDataObjCollection(mDataObject);
if (dataObjCol) {
uint32_t cnt = dataObjCol->GetNumDataObjects();
for (uint32_t i=0;i<cnt;++i) {
IDataObject * dataObj = dataObjCol->GetDataObjectAt(i);
if (S_OK == dataObj->QueryGetData(&fe))
*_retval = true; // found it!
}
}
} // if special collection object
else {
// Ok, so we have a single object. Check to see if has the correct
// data type. Since this can come from an outside app, we also
// need to see if we need to perform text->unicode conversion if
// the client asked for unicode and it wasn't available.
format = nsClipboard::GetFormat(aDataFlavor);
SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1,
TYMED_HGLOBAL | TYMED_FILE | TYMED_GDI);
if (mDataObject->QueryGetData(&fe) == S_OK)
*_retval = true; // found it!
else {
// We haven't found the exact flavor the client asked for, but
// maybe we can still find it from something else that's on the
// clipboard
if (strcmp(aDataFlavor, kUnicodeMime) == 0) {
// client asked for unicode and it wasn't present, check if we
// have CF_TEXT. We'll handle the actual data substitution in
// the data object.
format = nsClipboard::GetFormat(kTextMime);
SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1,
TYMED_HGLOBAL | TYMED_FILE | TYMED_GDI);
if (mDataObject->QueryGetData(&fe) == S_OK)
*_retval = true; // found it!
}
else if (strcmp(aDataFlavor, kURLMime) == 0) {
// client asked for a url and it wasn't present, but if we
// have a file, then we have a URL to give them (the path, or
// the internal URL if an InternetShortcut).
format = nsClipboard::GetFormat(kFileMime);
SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1,
TYMED_HGLOBAL | TYMED_FILE | TYMED_GDI);
if (mDataObject->QueryGetData(&fe) == S_OK)
*_retval = true; // found it!
}
} // else try again
}
return NS_OK;
}
//
// IsCollectionObject
//
// Determine if this is a single |IDataObject| or one of our private
// collection objects. We know the difference because our collection
// object will respond to supporting the private |MULTI_MIME| format.
//
bool
nsDragService::IsCollectionObject(IDataObject* inDataObj)
{
bool isCollection = false;
// setup the format object to ask for the MULTI_MIME format. We only
// need to do this once
static UINT sFormat = 0;
static FORMATETC sFE;
if (!sFormat) {
sFormat = nsClipboard::GetFormat(MULTI_MIME);
SET_FORMATETC(sFE, sFormat, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
}
// ask the object if it supports it. If yes, we have a collection
// object
if (inDataObj->QueryGetData(&sFE) == S_OK)
isCollection = true;
return isCollection;
} // IsCollectionObject
//
// EndDragSession
//
// Override the default to make sure that we release the data object
// when the drag ends. It seems that OLE doesn't like to let apps quit
// w/out crashing when we're still holding onto their data
//
NS_IMETHODIMP
nsDragService::EndDragSession(bool aDoneDrag)
{
// Bug 100180: If we've got mouse events captured, make sure we release it -
// that way, if we happen to call EndDragSession before diving into a nested
// event loop, we can still respond to mouse events.
if (::GetCapture()) {
::ReleaseCapture();
}
nsBaseDragService::EndDragSession(aDoneDrag);
NS_IF_RELEASE(mDataObject);
return NS_OK;
}

View file

@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsDragService_h__
#define nsDragService_h__
#include "nsBaseDragService.h"
#include <windows.h>
#include <shlobj.h>
struct IDataObject;
class nsDataObjCollection;
/**
* Native Win32 DragService wrapper
*/
class nsDragService : public nsBaseDragService
{
public:
nsDragService();
virtual ~nsDragService();
// nsBaseDragService
virtual nsresult InvokeDragSessionImpl(nsIArray* anArrayTransferables,
nsIScriptableRegion* aRegion,
uint32_t aActionType);
// nsIDragSession
NS_IMETHOD GetData(nsITransferable * aTransferable, uint32_t anItem);
NS_IMETHOD GetNumDropItems(uint32_t * aNumItems);
NS_IMETHOD IsDataFlavorSupported(const char *aDataFlavor, bool *_retval);
NS_IMETHOD EndDragSession(bool aDoneDrag);
// native impl.
NS_IMETHOD SetIDataObject(IDataObject * aDataObj);
NS_IMETHOD StartInvokingDragSession(IDataObject * aDataObj,
uint32_t aActionType);
// A drop occurred within the application vs. outside of it.
void SetDroppedLocal();
protected:
nsDataObjCollection* GetDataObjCollection(IDataObject * aDataObj);
// determine if we have a single data object or one of our private
// collections
bool IsCollectionObject(IDataObject* inDataObj);
// Create a bitmap for drag operations
bool CreateDragImage(nsIDOMNode *aDOMNode,
nsIScriptableRegion *aRegion,
SHDRAGIMAGE *psdi);
IDataObject * mDataObject;
bool mSentLocalDropEvent;
};
#endif // nsDragService_h__

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,164 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsFilePicker_h__
#define nsFilePicker_h__
#include <windows.h>
// For Vista IFileDialog interfaces which aren't exposed
// unless _WIN32_WINNT >= _WIN32_WINNT_LONGHORN.
#if _WIN32_WINNT < _WIN32_WINNT_LONGHORN
#define _WIN32_WINNT_bak _WIN32_WINNT
#undef _WIN32_WINNT
#define _WIN32_WINNT _WIN32_WINNT_LONGHORN
#define _WIN32_IE_bak _WIN32_IE
#undef _WIN32_IE
#define _WIN32_IE _WIN32_IE_IE70
#endif
#include "nsIFile.h"
#include "nsITimer.h"
#include "nsISimpleEnumerator.h"
#include "nsCOMArray.h"
#include "nsBaseFilePicker.h"
#include "nsString.h"
#include "nsdefs.h"
#include <commdlg.h>
#include <shobjidl.h>
#undef LogSeverity // SetupAPI.h #defines this as DWORD
class nsILoadContext;
class nsBaseWinFilePicker :
public nsBaseFilePicker
{
public:
NS_IMETHOD GetDefaultString(nsAString& aDefaultString);
NS_IMETHOD SetDefaultString(const nsAString& aDefaultString);
NS_IMETHOD GetDefaultExtension(nsAString& aDefaultExtension);
NS_IMETHOD SetDefaultExtension(const nsAString& aDefaultExtension);
protected:
nsString mDefaultFilePath;
nsString mDefaultFilename;
nsString mDefaultExtension;
};
/**
* Native Windows FileSelector wrapper
*/
class nsFilePicker :
public IFileDialogEvents,
public nsBaseWinFilePicker
{
virtual ~nsFilePicker();
public:
nsFilePicker();
NS_IMETHOD Init(mozIDOMWindowProxy *aParent, const nsAString& aTitle, int16_t aMode);
NS_DECL_ISUPPORTS
// IUnknown's QueryInterface
STDMETHODIMP QueryInterface(REFIID refiid, void** ppvResult);
// nsIFilePicker (less what's in nsBaseFilePicker and nsBaseWinFilePicker)
NS_IMETHOD GetFilterIndex(int32_t *aFilterIndex);
NS_IMETHOD SetFilterIndex(int32_t aFilterIndex);
NS_IMETHOD GetFile(nsIFile * *aFile);
NS_IMETHOD GetFileURL(nsIURI * *aFileURL);
NS_IMETHOD GetFiles(nsISimpleEnumerator **aFiles);
NS_IMETHOD Show(int16_t *aReturnVal);
NS_IMETHOD ShowW(int16_t *aReturnVal);
NS_IMETHOD AppendFilter(const nsAString& aTitle, const nsAString& aFilter);
// IFileDialogEvents
HRESULT STDMETHODCALLTYPE OnFileOk(IFileDialog *pfd);
HRESULT STDMETHODCALLTYPE OnFolderChanging(IFileDialog *pfd, IShellItem *psiFolder);
HRESULT STDMETHODCALLTYPE OnFolderChange(IFileDialog *pfd);
HRESULT STDMETHODCALLTYPE OnSelectionChange(IFileDialog *pfd);
HRESULT STDMETHODCALLTYPE OnShareViolation(IFileDialog *pfd, IShellItem *psi, FDE_SHAREVIOLATION_RESPONSE *pResponse);
HRESULT STDMETHODCALLTYPE OnTypeChange(IFileDialog *pfd);
HRESULT STDMETHODCALLTYPE OnOverwrite(IFileDialog *pfd, IShellItem *psi, FDE_OVERWRITE_RESPONSE *pResponse);
protected:
enum PickerType {
PICKER_TYPE_OPEN,
PICKER_TYPE_SAVE,
};
/* method from nsBaseFilePicker */
virtual void InitNative(nsIWidget *aParent,
const nsAString& aTitle);
static void GetQualifiedPath(const wchar_t *aInPath, nsString &aOutPath);
void GetFilterListArray(nsString& aFilterList);
static bool GetFileNameWrapper(OPENFILENAMEW* ofn, PickerType aType);
bool FilePickerWrapper(OPENFILENAMEW* ofn, PickerType aType);
bool ShowXPFolderPicker(const nsString& aInitialDir);
bool ShowXPFilePicker(const nsString& aInitialDir);
bool ShowFolderPicker(const nsString& aInitialDir, bool &aWasInitError);
bool ShowFilePicker(const nsString& aInitialDir, bool &aWasInitError);
void AppendXPFilter(const nsAString& aTitle, const nsAString& aFilter);
void RememberLastUsedDirectory();
bool IsPrivacyModeEnabled();
bool IsDefaultPathLink();
bool IsDefaultPathHtml();
void SetDialogHandle(HWND aWnd);
bool ClosePickerIfNeeded(bool aIsXPDialog);
static void PickerCallbackTimerFunc(nsITimer *aTimer, void *aPicker);
static UINT_PTR CALLBACK MultiFilePickerHook(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
static UINT_PTR CALLBACK FilePickerHook(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
nsCOMPtr<nsILoadContext> mLoadContext;
nsCOMPtr<nsIWidget> mParentWidget;
nsString mTitle;
nsCString mFile;
nsString mFilterList;
int16_t mSelectedType;
nsCOMArray<nsIFile> mFiles;
static char mLastUsedDirectory[];
nsString mUnicodeFile;
static char16_t *mLastUsedUnicodeDirectory;
HWND mDlgWnd;
class ComDlgFilterSpec
{
public:
ComDlgFilterSpec() {}
~ComDlgFilterSpec() {}
const uint32_t Length() {
return mSpecList.Length();
}
const bool IsEmpty() {
return (mSpecList.Length() == 0);
}
const COMDLG_FILTERSPEC* get() {
return mSpecList.Elements();
}
void Append(const nsAString& aTitle, const nsAString& aFilter);
private:
AutoTArray<COMDLG_FILTERSPEC, 1> mSpecList;
AutoTArray<nsString, 2> mStrings;
};
ComDlgFilterSpec mComFilterList;
DWORD mFDECookie;
};
#if defined(_WIN32_WINNT_bak)
#undef _WIN32_WINNT
#define _WIN32_WINNT _WIN32_WINNT_bak
#undef _WIN32_IE
#define _WIN32_IE _WIN32_IE_bak
#endif
#endif // nsFilePicker_h__

View file

@ -0,0 +1,30 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim:expandtab:shiftwidth=4:tabstop=4:
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIdleServiceWin.h"
#include <windows.h>
NS_IMPL_ISUPPORTS_INHERITED0(nsIdleServiceWin, nsIdleService)
bool
nsIdleServiceWin::PollIdleTime(uint32_t *aIdleTime)
{
LASTINPUTINFO inputInfo;
inputInfo.cbSize = sizeof(inputInfo);
if (!::GetLastInputInfo(&inputInfo))
return false;
*aIdleTime = SAFE_COMPARE_EVEN_WITH_WRAPPING(GetTickCount(), inputInfo.dwTime);
return true;
}
bool
nsIdleServiceWin::UsePollMode()
{
return true;
}

View file

@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim:expandtab:shiftwidth=4:tabstop=4:
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsIdleServiceWin_h__
#define nsIdleServiceWin_h__
#include "nsIdleService.h"
/* NOTE: Compare of GetTickCount() could overflow. This corrects for
* overflow situations.
***/
#ifndef SAFE_COMPARE_EVEN_WITH_WRAPPING
#define SAFE_COMPARE_EVEN_WITH_WRAPPING(A, B) (((int)((long)A - (long)B) & 0xFFFFFFFF))
#endif
class nsIdleServiceWin : public nsIdleService
{
public:
NS_DECL_ISUPPORTS_INHERITED
bool PollIdleTime(uint32_t* aIdleTime) override;
static already_AddRefed<nsIdleServiceWin> GetInstance()
{
RefPtr<nsIdleServiceWin> idleService =
nsIdleService::GetInstance().downcast<nsIdleServiceWin>();
if (!idleService) {
idleService = new nsIdleServiceWin();
}
return idleService.forget();
}
protected:
nsIdleServiceWin() { }
virtual ~nsIdleServiceWin() { }
bool UsePollMode() override;
};
#endif // nsIdleServiceWin_h__

View file

@ -0,0 +1,497 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsImageClipboard.h"
#include "gfxUtils.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/DataSurfaceHelpers.h"
#include "mozilla/RefPtr.h"
#include "nsITransferable.h"
#include "nsGfxCIID.h"
#include "nsMemory.h"
#include "prmem.h"
#include "imgIEncoder.h"
#include "nsLiteralString.h"
#include "nsComponentManagerUtils.h"
#define BFH_LENGTH 14
using namespace mozilla;
using namespace mozilla::gfx;
/* Things To Do 11/8/00
Check image metrics, can we support them? Do we need to?
Any other render format? HTML?
*/
//
// nsImageToClipboard ctor
//
// Given an imgIContainer, convert it to a DIB that is ready to go on the win32 clipboard
//
nsImageToClipboard::nsImageToClipboard(imgIContainer* aInImage, bool aWantDIBV5)
: mImage(aInImage)
, mWantDIBV5(aWantDIBV5)
{
// nothing to do here
}
//
// nsImageToClipboard dtor
//
// Clean up after ourselves. We know that we have created the bitmap
// successfully if we still have a pointer to the header.
//
nsImageToClipboard::~nsImageToClipboard()
{
}
//
// GetPicture
//
// Call to get the actual bits that go on the clipboard. If an error
// ocurred during conversion, |outBits| will be null.
//
// NOTE: The caller owns the handle and must delete it with ::GlobalRelease()
//
nsresult
nsImageToClipboard :: GetPicture ( HANDLE* outBits )
{
NS_ASSERTION ( outBits, "Bad parameter" );
return CreateFromImage ( mImage, outBits );
} // GetPicture
//
// CalcSize
//
// Computes # of bytes needed by a bitmap with the specified attributes.
//
int32_t
nsImageToClipboard :: CalcSize ( int32_t aHeight, int32_t aColors, WORD aBitsPerPixel, int32_t aSpanBytes )
{
int32_t HeaderMem = sizeof(BITMAPINFOHEADER);
// add size of pallette to header size
if (aBitsPerPixel < 16)
HeaderMem += aColors * sizeof(RGBQUAD);
if (aHeight < 0)
aHeight = -aHeight;
return (HeaderMem + (aHeight * aSpanBytes));
}
//
// CalcSpanLength
//
// Computes the span bytes for determining the overall size of the image
//
int32_t
nsImageToClipboard::CalcSpanLength(uint32_t aWidth, uint32_t aBitCount)
{
int32_t spanBytes = (aWidth * aBitCount) >> 5;
if ((aWidth * aBitCount) & 0x1F)
spanBytes++;
spanBytes <<= 2;
return spanBytes;
}
//
// CreateFromImage
//
// Do the work to setup the bitmap header and copy the bits out of the
// image.
//
nsresult
nsImageToClipboard::CreateFromImage ( imgIContainer* inImage, HANDLE* outBitmap )
{
nsresult rv;
*outBitmap = nullptr;
RefPtr<SourceSurface> surface =
inImage->GetFrame(imgIContainer::FRAME_CURRENT,
imgIContainer::FLAG_SYNC_DECODE);
NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE);
MOZ_ASSERT(surface->GetFormat() == SurfaceFormat::B8G8R8A8 ||
surface->GetFormat() == SurfaceFormat::B8G8R8X8);
RefPtr<DataSourceSurface> dataSurface;
if (surface->GetFormat() == SurfaceFormat::B8G8R8A8) {
dataSurface = surface->GetDataSurface();
} else {
// XXXjwatt Bug 995923 - get rid of this copy and handle B8G8R8X8
// directly below once bug 995807 is fixed.
dataSurface = gfxUtils::
CopySurfaceToDataSourceSurfaceWithFormat(surface,
SurfaceFormat::B8G8R8A8);
}
NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance("@mozilla.org/image/encoder;2?type=image/bmp", &rv);
NS_ENSURE_SUCCESS(rv, rv);
uint32_t format;
nsAutoString options;
if (mWantDIBV5) {
options.AppendLiteral("version=5;bpp=");
} else {
options.AppendLiteral("version=3;bpp=");
}
switch (dataSurface->GetFormat()) {
case SurfaceFormat::B8G8R8A8:
format = imgIEncoder::INPUT_FORMAT_HOSTARGB;
options.AppendInt(32);
break;
#if 0
// XXXjwatt Bug 995923 - fix |format| and reenable once bug 995807 is fixed.
case SurfaceFormat::B8G8R8X8:
format = imgIEncoder::INPUT_FORMAT_RGB;
options.AppendInt(24);
break;
#endif
default:
NS_NOTREACHED("Unexpected surface format");
return NS_ERROR_INVALID_ARG;
}
DataSourceSurface::MappedSurface map;
bool mappedOK = dataSurface->Map(DataSourceSurface::MapType::READ, &map);
NS_ENSURE_TRUE(mappedOK, NS_ERROR_FAILURE);
rv = encoder->InitFromData(map.mData, 0,
dataSurface->GetSize().width,
dataSurface->GetSize().height,
map.mStride,
format, options);
dataSurface->Unmap();
NS_ENSURE_SUCCESS(rv, rv);
uint32_t size;
encoder->GetImageBufferUsed(&size);
NS_ENSURE_TRUE(size > BFH_LENGTH, NS_ERROR_FAILURE);
HGLOBAL glob = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT,
size - BFH_LENGTH);
if (!glob)
return NS_ERROR_OUT_OF_MEMORY;
char *dst = (char*) ::GlobalLock(glob);
char *src;
rv = encoder->GetImageBuffer(&src);
NS_ENSURE_SUCCESS(rv, rv);
::CopyMemory(dst, src + BFH_LENGTH, size - BFH_LENGTH);
::GlobalUnlock(glob);
*outBitmap = (HANDLE)glob;
return NS_OK;
}
nsImageFromClipboard :: nsImageFromClipboard ()
{
// nothing to do here
}
nsImageFromClipboard :: ~nsImageFromClipboard ( )
{
}
//
// GetEncodedImageStream
//
// Take the raw clipboard image data and convert it to aMIMEFormat in the form of a nsIInputStream
//
nsresult
nsImageFromClipboard ::GetEncodedImageStream (unsigned char * aClipboardData, const char * aMIMEFormat, nsIInputStream** aInputStream )
{
NS_ENSURE_ARG_POINTER (aInputStream);
NS_ENSURE_ARG_POINTER (aMIMEFormat);
nsresult rv;
*aInputStream = nullptr;
// pull the size information out of the BITMAPINFO header and
// initialize the image
BITMAPINFO* header = (BITMAPINFO *) aClipboardData;
int32_t width = header->bmiHeader.biWidth;
int32_t height = header->bmiHeader.biHeight;
// neg. heights mean the Y axis is inverted and we don't handle that case
NS_ENSURE_TRUE(height > 0, NS_ERROR_FAILURE);
unsigned char * rgbData = new unsigned char[width * height * 3 /* RGB */];
if (rgbData) {
BYTE * pGlobal = (BYTE *) aClipboardData;
// Convert the clipboard image into RGB packed pixel data
rv = ConvertColorBitMap((unsigned char *) (pGlobal + header->bmiHeader.biSize), header, rgbData);
// if that succeeded, encode the bitmap as aMIMEFormat data. Don't return early or we risk leaking rgbData
if (NS_SUCCEEDED(rv)) {
nsAutoCString encoderCID(NS_LITERAL_CSTRING("@mozilla.org/image/encoder;2?type="));
// Map image/jpg to image/jpeg (which is how the encoder is registered).
if (strcmp(aMIMEFormat, kJPGImageMime) == 0)
encoderCID.AppendLiteral("image/jpeg");
else
encoderCID.Append(aMIMEFormat);
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(encoderCID.get(), &rv);
if (NS_SUCCEEDED(rv)){
rv = encoder->InitFromData(rgbData, 0, width, height, 3 * width /* RGB * # pixels in a row */,
imgIEncoder::INPUT_FORMAT_RGB, EmptyString());
if (NS_SUCCEEDED(rv)) {
encoder.forget(aInputStream);
}
}
}
delete [] rgbData;
}
else
rv = NS_ERROR_OUT_OF_MEMORY;
return rv;
} // GetImage
//
// InvertRows
//
// Take the image data from the clipboard and invert the rows. Modifying aInitialBuffer in place.
//
void
nsImageFromClipboard::InvertRows(unsigned char * aInitialBuffer, uint32_t aSizeOfBuffer, uint32_t aNumBytesPerRow)
{
if (!aNumBytesPerRow)
return;
uint32_t numRows = aSizeOfBuffer / aNumBytesPerRow;
unsigned char * row = new unsigned char[aNumBytesPerRow];
uint32_t currentRow = 0;
uint32_t lastRow = (numRows - 1) * aNumBytesPerRow;
while (currentRow < lastRow)
{
// store the current row into a temporary buffer
memcpy(row, &aInitialBuffer[currentRow], aNumBytesPerRow);
memcpy(&aInitialBuffer[currentRow], &aInitialBuffer[lastRow], aNumBytesPerRow);
memcpy(&aInitialBuffer[lastRow], row, aNumBytesPerRow);
lastRow -= aNumBytesPerRow;
currentRow += aNumBytesPerRow;
}
delete[] row;
}
//
// ConvertColorBitMap
//
// Takes the clipboard bitmap and converts it into a RGB packed pixel values.
//
nsresult
nsImageFromClipboard::ConvertColorBitMap(unsigned char * aInputBuffer, PBITMAPINFO pBitMapInfo, unsigned char * aOutBuffer)
{
uint8_t bitCount = pBitMapInfo->bmiHeader.biBitCount;
uint32_t imageSize = pBitMapInfo->bmiHeader.biSizeImage; // may be zero for BI_RGB bitmaps which means we need to calculate by hand
uint32_t bytesPerPixel = bitCount / 8;
if (bitCount <= 4)
bytesPerPixel = 1;
// rows are DWORD aligned. Calculate how many real bytes are in each row in the bitmap. This number won't
// correspond to biWidth.
uint32_t rowSize = (bitCount * pBitMapInfo->bmiHeader.biWidth + 7) / 8; // +7 to round up
if (rowSize % 4)
rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
// if our buffer includes a color map, skip over it
if (bitCount <= 8)
{
int32_t bytesToSkip = (pBitMapInfo->bmiHeader.biClrUsed ? pBitMapInfo->bmiHeader.biClrUsed : (1 << bitCount) ) * sizeof(RGBQUAD);
aInputBuffer += bytesToSkip;
}
bitFields colorMasks; // only used if biCompression == BI_BITFIELDS
if (pBitMapInfo->bmiHeader.biCompression == BI_BITFIELDS)
{
// color table consists of 3 DWORDS containing the color masks...
colorMasks.red = (*((uint32_t*)&(pBitMapInfo->bmiColors[0])));
colorMasks.green = (*((uint32_t*)&(pBitMapInfo->bmiColors[1])));
colorMasks.blue = (*((uint32_t*)&(pBitMapInfo->bmiColors[2])));
CalcBitShift(&colorMasks);
aInputBuffer += 3 * sizeof(DWORD);
}
else if (pBitMapInfo->bmiHeader.biCompression == BI_RGB && !imageSize) // BI_RGB can have a size of zero which means we figure it out
{
// XXX: note use rowSize here and not biWidth. rowSize accounts for the DWORD padding for each row
imageSize = rowSize * pBitMapInfo->bmiHeader.biHeight;
}
// The windows clipboard image format inverts the rows
InvertRows(aInputBuffer, imageSize, rowSize);
if (!pBitMapInfo->bmiHeader.biCompression || pBitMapInfo->bmiHeader.biCompression == BI_BITFIELDS)
{
uint32_t index = 0;
uint32_t writeIndex = 0;
unsigned char redValue, greenValue, blueValue;
uint8_t colorTableEntry = 0;
int8_t bit; // used for grayscale bitmaps where each bit is a pixel
uint32_t numPixelsLeftInRow = pBitMapInfo->bmiHeader.biWidth; // how many more pixels do we still need to read for the current row
uint32_t pos = 0;
while (index < imageSize)
{
switch (bitCount)
{
case 1:
for (bit = 7; bit >= 0 && numPixelsLeftInRow; bit--)
{
colorTableEntry = (aInputBuffer[index] >> bit) & 1;
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbRed;
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbGreen;
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbBlue;
numPixelsLeftInRow--;
}
pos += 1;
break;
case 4:
{
// each aInputBuffer[index] entry contains data for two pixels.
// read the first pixel
colorTableEntry = aInputBuffer[index] >> 4;
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbRed;
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbGreen;
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbBlue;
numPixelsLeftInRow--;
if (numPixelsLeftInRow) // now read the second pixel
{
colorTableEntry = aInputBuffer[index] & 0xF;
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbRed;
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbGreen;
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbBlue;
numPixelsLeftInRow--;
}
pos += 1;
}
break;
case 8:
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[aInputBuffer[index]].rgbRed;
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[aInputBuffer[index]].rgbGreen;
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[aInputBuffer[index]].rgbBlue;
numPixelsLeftInRow--;
pos += 1;
break;
case 16:
{
uint16_t num = 0;
num = (uint8_t) aInputBuffer[index+1];
num <<= 8;
num |= (uint8_t) aInputBuffer[index];
redValue = ((uint32_t) (((float)(num & 0xf800) / 0xf800) * 0xFF0000) & 0xFF0000)>> 16;
greenValue = ((uint32_t)(((float)(num & 0x07E0) / 0x07E0) * 0x00FF00) & 0x00FF00)>> 8;
blueValue = ((uint32_t)(((float)(num & 0x001F) / 0x001F) * 0x0000FF) & 0x0000FF);
// now we have the right RGB values...
aOutBuffer[writeIndex++] = redValue;
aOutBuffer[writeIndex++] = greenValue;
aOutBuffer[writeIndex++] = blueValue;
numPixelsLeftInRow--;
pos += 2;
}
break;
case 32:
case 24:
if (pBitMapInfo->bmiHeader.biCompression == BI_BITFIELDS)
{
uint32_t val = *((uint32_t*) (aInputBuffer + index) );
aOutBuffer[writeIndex++] = (val & colorMasks.red) >> colorMasks.redRightShift << colorMasks.redLeftShift;
aOutBuffer[writeIndex++] = (val & colorMasks.green) >> colorMasks.greenRightShift << colorMasks.greenLeftShift;
aOutBuffer[writeIndex++] = (val & colorMasks.blue) >> colorMasks.blueRightShift << colorMasks.blueLeftShift;
numPixelsLeftInRow--;
pos += 4; // we read in 4 bytes of data in order to process this pixel
}
else
{
aOutBuffer[writeIndex++] = aInputBuffer[index+2];
aOutBuffer[writeIndex++] = aInputBuffer[index+1];
aOutBuffer[writeIndex++] = aInputBuffer[index];
numPixelsLeftInRow--;
pos += bytesPerPixel; // 3 bytes for 24 bit data, 4 bytes for 32 bit data (we skip over the 4th byte)...
}
break;
default:
// This is probably the wrong place to check this...
return NS_ERROR_FAILURE;
}
index += bytesPerPixel; // increment our loop counter
if (!numPixelsLeftInRow)
{
if (rowSize != pos)
{
// advance index to skip over remaining padding bytes
index += (rowSize - pos);
}
numPixelsLeftInRow = pBitMapInfo->bmiHeader.biWidth;
pos = 0;
}
} // while we still have bytes to process
}
return NS_OK;
}
void nsImageFromClipboard::CalcBitmask(uint32_t aMask, uint8_t& aBegin, uint8_t& aLength)
{
// find the rightmost 1
uint8_t pos;
bool started = false;
aBegin = aLength = 0;
for (pos = 0; pos <= 31; pos++)
{
if (!started && (aMask & (1 << pos)))
{
aBegin = pos;
started = true;
}
else if (started && !(aMask & (1 << pos)))
{
aLength = pos - aBegin;
break;
}
}
}
void nsImageFromClipboard::CalcBitShift(bitFields * aColorMask)
{
uint8_t begin, length;
// red
CalcBitmask(aColorMask->red, begin, length);
aColorMask->redRightShift = begin;
aColorMask->redLeftShift = 8 - length;
// green
CalcBitmask(aColorMask->green, begin, length);
aColorMask->greenRightShift = begin;
aColorMask->greenLeftShift = 8 - length;
// blue
CalcBitmask(aColorMask->blue, begin, length);
aColorMask->blueRightShift = begin;
aColorMask->blueLeftShift = 8 - length;
}

View file

@ -0,0 +1,93 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsImageClipboard_h
#define nsImageClipboard_h
/* Things To Do 11/8/00
Check image metrics, can we support them? Do we need to?
Any other render format? HTML?
*/
#include "nsError.h"
#include <windows.h>
#include "nsCOMPtr.h"
#include "imgIContainer.h"
#include "nsIInputStream.h"
//
// nsImageToClipboard
//
// A utility class that takes an imgIContainer and does all the bitmap magic
// to allow us to put it on the clipboard
//
class nsImageToClipboard
{
public:
nsImageToClipboard(imgIContainer* aInImage, bool aWantDIBV5 = true);
~nsImageToClipboard();
// Call to get the actual bits that go on the clipboard. If |nullptr|, the
// setup operations have failed.
//
// NOTE: The caller owns the handle and must delete it with ::GlobalRelease()
nsresult GetPicture ( HANDLE* outBits ) ;
private:
// Computes # of bytes needed by a bitmap with the specified attributes.
int32_t CalcSize(int32_t aHeight, int32_t aColors, WORD aBitsPerPixel, int32_t aSpanBytes);
int32_t CalcSpanLength(uint32_t aWidth, uint32_t aBitCount);
// Do the work
nsresult CreateFromImage ( imgIContainer* inImage, HANDLE* outBitmap );
nsCOMPtr<imgIContainer> mImage; // the image we're working with
bool mWantDIBV5;
}; // class nsImageToClipboard
struct bitFields {
uint32_t red;
uint32_t green;
uint32_t blue;
uint8_t redLeftShift;
uint8_t redRightShift;
uint8_t greenLeftShift;
uint8_t greenRightShift;
uint8_t blueLeftShift;
uint8_t blueRightShift;
};
//
// nsImageFromClipboard
//
// A utility class that takes a DIB from the win32 clipboard and does
// all the bitmap magic to convert it to a PNG or a JPEG in the form of a nsIInputStream
//
class nsImageFromClipboard
{
public:
nsImageFromClipboard () ;
~nsImageFromClipboard ( ) ;
// Retrieve the newly created image
nsresult GetEncodedImageStream (unsigned char * aClipboardData, const char * aMIMEFormat, nsIInputStream** outImage);
private:
void InvertRows(unsigned char * aInitialBuffer, uint32_t aSizeOfBuffer, uint32_t aNumBytesPerRow);
nsresult ConvertColorBitMap(unsigned char * aInputBuffer, PBITMAPINFO pBitMapInfo, unsigned char * aOutBuffer);
void CalcBitmask(uint32_t aMask, uint8_t& aBegin, uint8_t& aLength);
void CalcBitShift(bitFields * aColorMask);
}; // nsImageFromClipboard
#endif

View file

@ -0,0 +1,701 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsLookAndFeel.h"
#include <windows.h>
#include <shellapi.h>
#include "nsStyleConsts.h"
#include "nsUXThemeData.h"
#include "nsUXThemeConstants.h"
#include "gfxFont.h"
#include "WinUtils.h"
#include "mozilla/Telemetry.h"
#include "mozilla/WindowsVersion.h"
#include "gfxFontConstants.h"
using namespace mozilla;
using namespace mozilla::widget;
//static
LookAndFeel::OperatingSystemVersion
nsLookAndFeel::GetOperatingSystemVersion()
{
static OperatingSystemVersion version = eOperatingSystemVersion_Unknown;
if (version != eOperatingSystemVersion_Unknown) {
return version;
}
if (IsWin10OrLater()) {
version = eOperatingSystemVersion_Windows10;
} else if (IsWin8OrLater()) {
version = eOperatingSystemVersion_Windows8;
} else if (IsWin7OrLater()) {
version = eOperatingSystemVersion_Windows7;
} else if (IsVistaOrLater()) {
version = eOperatingSystemVersion_WindowsVista;
} else {
version = eOperatingSystemVersion_WindowsXP;
}
return version;
}
static nsresult GetColorFromTheme(nsUXThemeClass cls,
int32_t aPart,
int32_t aState,
int32_t aPropId,
nscolor &aColor)
{
COLORREF color;
HRESULT hr = GetThemeColor(nsUXThemeData::GetTheme(cls), aPart, aState, aPropId, &color);
if (hr == S_OK)
{
aColor = COLOREF_2_NSRGB(color);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
static int32_t GetSystemParam(long flag, int32_t def)
{
DWORD value;
return ::SystemParametersInfo(flag, 0, &value, 0) ? value : def;
}
nsLookAndFeel::nsLookAndFeel()
: nsXPLookAndFeel()
, mUseAccessibilityTheme(0)
{
mozilla::Telemetry::Accumulate(mozilla::Telemetry::TOUCH_ENABLED_DEVICE,
WinUtils::IsTouchDeviceSupportPresent());
}
nsLookAndFeel::~nsLookAndFeel()
{
}
nsresult
nsLookAndFeel::NativeGetColor(ColorID aID, nscolor &aColor)
{
nsresult res = NS_OK;
int idx;
switch (aID) {
case eColorID_WindowBackground:
idx = COLOR_WINDOW;
break;
case eColorID_WindowForeground:
idx = COLOR_WINDOWTEXT;
break;
case eColorID_WidgetBackground:
idx = COLOR_BTNFACE;
break;
case eColorID_WidgetForeground:
idx = COLOR_BTNTEXT;
break;
case eColorID_WidgetSelectBackground:
idx = COLOR_HIGHLIGHT;
break;
case eColorID_WidgetSelectForeground:
idx = COLOR_HIGHLIGHTTEXT;
break;
case eColorID_Widget3DHighlight:
idx = COLOR_BTNHIGHLIGHT;
break;
case eColorID_Widget3DShadow:
idx = COLOR_BTNSHADOW;
break;
case eColorID_TextBackground:
idx = COLOR_WINDOW;
break;
case eColorID_TextForeground:
idx = COLOR_WINDOWTEXT;
break;
case eColorID_TextSelectBackground:
case eColorID_IMESelectedRawTextBackground:
case eColorID_IMESelectedConvertedTextBackground:
idx = COLOR_HIGHLIGHT;
break;
case eColorID_TextSelectForeground:
case eColorID_IMESelectedRawTextForeground:
case eColorID_IMESelectedConvertedTextForeground:
idx = COLOR_HIGHLIGHTTEXT;
break;
case eColorID_IMERawInputBackground:
case eColorID_IMEConvertedTextBackground:
aColor = NS_TRANSPARENT;
return NS_OK;
case eColorID_IMERawInputForeground:
case eColorID_IMEConvertedTextForeground:
aColor = NS_SAME_AS_FOREGROUND_COLOR;
return NS_OK;
case eColorID_IMERawInputUnderline:
case eColorID_IMEConvertedTextUnderline:
aColor = NS_SAME_AS_FOREGROUND_COLOR;
return NS_OK;
case eColorID_IMESelectedRawTextUnderline:
case eColorID_IMESelectedConvertedTextUnderline:
aColor = NS_TRANSPARENT;
return NS_OK;
case eColorID_SpellCheckerUnderline:
aColor = NS_RGB(0xff, 0, 0);
return NS_OK;
// New CSS 2 Color definitions
case eColorID_activeborder:
idx = COLOR_ACTIVEBORDER;
break;
case eColorID_activecaption:
idx = COLOR_ACTIVECAPTION;
break;
case eColorID_appworkspace:
idx = COLOR_APPWORKSPACE;
break;
case eColorID_background:
idx = COLOR_BACKGROUND;
break;
case eColorID_buttonface:
case eColorID__moz_buttonhoverface:
idx = COLOR_BTNFACE;
break;
case eColorID_buttonhighlight:
idx = COLOR_BTNHIGHLIGHT;
break;
case eColorID_buttonshadow:
idx = COLOR_BTNSHADOW;
break;
case eColorID_buttontext:
case eColorID__moz_buttonhovertext:
idx = COLOR_BTNTEXT;
break;
case eColorID_captiontext:
idx = COLOR_CAPTIONTEXT;
break;
case eColorID_graytext:
idx = COLOR_GRAYTEXT;
break;
case eColorID_highlight:
case eColorID__moz_html_cellhighlight:
case eColorID__moz_menuhover:
idx = COLOR_HIGHLIGHT;
break;
case eColorID__moz_menubarhovertext:
if (!IsVistaOrLater() || !IsAppThemed())
{
idx = nsUXThemeData::sFlatMenus ?
COLOR_HIGHLIGHTTEXT :
COLOR_MENUTEXT;
break;
}
// Fall through
case eColorID__moz_menuhovertext:
if (IsVistaOrLater() && IsAppThemed())
{
res = ::GetColorFromTheme(eUXMenu,
MENU_POPUPITEM, MPI_HOT, TMT_TEXTCOLOR, aColor);
if (NS_SUCCEEDED(res))
return res;
// fall through to highlight case
}
case eColorID_highlighttext:
case eColorID__moz_html_cellhighlighttext:
idx = COLOR_HIGHLIGHTTEXT;
break;
case eColorID_inactiveborder:
idx = COLOR_INACTIVEBORDER;
break;
case eColorID_inactivecaption:
idx = COLOR_INACTIVECAPTION;
break;
case eColorID_inactivecaptiontext:
idx = COLOR_INACTIVECAPTIONTEXT;
break;
case eColorID_infobackground:
idx = COLOR_INFOBK;
break;
case eColorID_infotext:
idx = COLOR_INFOTEXT;
break;
case eColorID_menu:
idx = COLOR_MENU;
break;
case eColorID_menutext:
case eColorID__moz_menubartext:
idx = COLOR_MENUTEXT;
break;
case eColorID_scrollbar:
idx = COLOR_SCROLLBAR;
break;
case eColorID_threeddarkshadow:
idx = COLOR_3DDKSHADOW;
break;
case eColorID_threedface:
idx = COLOR_3DFACE;
break;
case eColorID_threedhighlight:
idx = COLOR_3DHIGHLIGHT;
break;
case eColorID_threedlightshadow:
idx = COLOR_3DLIGHT;
break;
case eColorID_threedshadow:
idx = COLOR_3DSHADOW;
break;
case eColorID_window:
idx = COLOR_WINDOW;
break;
case eColorID_windowframe:
idx = COLOR_WINDOWFRAME;
break;
case eColorID_windowtext:
idx = COLOR_WINDOWTEXT;
break;
case eColorID__moz_eventreerow:
case eColorID__moz_oddtreerow:
case eColorID__moz_field:
case eColorID__moz_combobox:
idx = COLOR_WINDOW;
break;
case eColorID__moz_fieldtext:
case eColorID__moz_comboboxtext:
idx = COLOR_WINDOWTEXT;
break;
case eColorID__moz_dialog:
case eColorID__moz_cellhighlight:
idx = COLOR_3DFACE;
break;
case eColorID__moz_win_mediatext:
if (IsVistaOrLater() && IsAppThemed()) {
res = ::GetColorFromTheme(eUXMediaToolbar,
TP_BUTTON, TS_NORMAL, TMT_TEXTCOLOR, aColor);
if (NS_SUCCEEDED(res))
return res;
}
// if we've gotten here just return -moz-dialogtext instead
idx = COLOR_WINDOWTEXT;
break;
case eColorID__moz_win_communicationstext:
if (IsVistaOrLater() && IsAppThemed())
{
res = ::GetColorFromTheme(eUXCommunicationsToolbar,
TP_BUTTON, TS_NORMAL, TMT_TEXTCOLOR, aColor);
if (NS_SUCCEEDED(res))
return res;
}
// if we've gotten here just return -moz-dialogtext instead
idx = COLOR_WINDOWTEXT;
break;
case eColorID__moz_dialogtext:
case eColorID__moz_cellhighlighttext:
idx = COLOR_WINDOWTEXT;
break;
case eColorID__moz_dragtargetzone:
idx = COLOR_HIGHLIGHTTEXT;
break;
case eColorID__moz_buttondefault:
idx = COLOR_3DDKSHADOW;
break;
case eColorID__moz_nativehyperlinktext:
idx = COLOR_HOTLIGHT;
break;
default:
idx = COLOR_WINDOW;
break;
}
DWORD color = ::GetSysColor(idx);
aColor = COLOREF_2_NSRGB(color);
return res;
}
nsresult
nsLookAndFeel::GetIntImpl(IntID aID, int32_t &aResult)
{
nsresult res = nsXPLookAndFeel::GetIntImpl(aID, aResult);
if (NS_SUCCEEDED(res))
return res;
res = NS_OK;
switch (aID) {
case eIntID_CaretBlinkTime:
aResult = (int32_t)::GetCaretBlinkTime();
break;
case eIntID_CaretWidth:
aResult = 1;
break;
case eIntID_ShowCaretDuringSelection:
aResult = 0;
break;
case eIntID_SelectTextfieldsOnKeyFocus:
// Select textfield content when focused by kbd
// used by EventStateManager::sTextfieldSelectModel
aResult = 1;
break;
case eIntID_SubmenuDelay:
// This will default to the Windows' default
// (400ms) on error.
aResult = GetSystemParam(SPI_GETMENUSHOWDELAY, 400);
break;
case eIntID_TooltipDelay:
aResult = 500;
break;
case eIntID_MenusCanOverlapOSBar:
// we want XUL popups to be able to overlap the task bar.
aResult = 1;
break;
case eIntID_DragThresholdX:
// The system metric is the number of pixels at which a drag should
// start. Our look and feel metric is the number of pixels you can
// move before starting a drag, so subtract 1.
aResult = ::GetSystemMetrics(SM_CXDRAG) - 1;
break;
case eIntID_DragThresholdY:
aResult = ::GetSystemMetrics(SM_CYDRAG) - 1;
break;
case eIntID_UseAccessibilityTheme:
// High contrast is a misnomer under Win32 -- any theme can be used with it,
// e.g. normal contrast with large fonts, low contrast, etc.
// The high contrast flag really means -- use this theme and don't override it.
if (XRE_IsContentProcess()) {
// If we're running in the content process, then the parent should
// have sent us the accessibility state when nsLookAndFeel
// initialized, and stashed it in the mUseAccessibilityTheme cache.
aResult = mUseAccessibilityTheme;
} else {
// Otherwise, we can ask the OS to see if we're using High Contrast
// mode.
aResult = nsUXThemeData::IsHighContrastOn();
}
break;
case eIntID_ScrollArrowStyle:
aResult = eScrollArrowStyle_Single;
break;
case eIntID_ScrollSliderStyle:
aResult = eScrollThumbStyle_Proportional;
break;
case eIntID_TreeOpenDelay:
aResult = 1000;
break;
case eIntID_TreeCloseDelay:
aResult = 0;
break;
case eIntID_TreeLazyScrollDelay:
aResult = 150;
break;
case eIntID_TreeScrollDelay:
aResult = 100;
break;
case eIntID_TreeScrollLinesMax:
aResult = 3;
break;
case eIntID_WindowsClassic:
aResult = !IsAppThemed();
break;
case eIntID_TouchEnabled:
aResult = WinUtils::IsTouchDeviceSupportPresent();
break;
case eIntID_WindowsDefaultTheme:
aResult = nsUXThemeData::IsDefaultWindowTheme();
break;
case eIntID_WindowsThemeIdentifier:
aResult = nsUXThemeData::GetNativeThemeId();
break;
case eIntID_OperatingSystemVersionIdentifier:
{
aResult = GetOperatingSystemVersion();
break;
}
case eIntID_MacGraphiteTheme:
aResult = 0;
res = NS_ERROR_NOT_IMPLEMENTED;
break;
case eIntID_DWMCompositor:
aResult = nsUXThemeData::CheckForCompositor();
break;
case eIntID_WindowsGlass:
// Aero Glass is only available prior to Windows 8 when DWM is used.
aResult = (nsUXThemeData::CheckForCompositor() && !IsWin8OrLater());
break;
case eIntID_AlertNotificationOrigin:
aResult = 0;
{
// Get task bar window handle
HWND shellWindow = FindWindowW(L"Shell_TrayWnd", nullptr);
if (shellWindow != nullptr)
{
// Determine position
APPBARDATA appBarData;
appBarData.hWnd = shellWindow;
appBarData.cbSize = sizeof(appBarData);
if (SHAppBarMessage(ABM_GETTASKBARPOS, &appBarData))
{
// Set alert origin as a bit field - see LookAndFeel.h
// 0 represents bottom right, sliding vertically.
switch(appBarData.uEdge)
{
case ABE_LEFT:
aResult = NS_ALERT_HORIZONTAL | NS_ALERT_LEFT;
break;
case ABE_RIGHT:
aResult = NS_ALERT_HORIZONTAL;
break;
case ABE_TOP:
aResult = NS_ALERT_TOP;
// fall through for the right-to-left handling.
case ABE_BOTTOM:
// If the task bar is right-to-left,
// move the origin to the left
if (::GetWindowLong(shellWindow, GWL_EXSTYLE) &
WS_EX_LAYOUTRTL)
aResult |= NS_ALERT_LEFT;
break;
}
}
}
}
break;
case eIntID_IMERawInputUnderlineStyle:
case eIntID_IMEConvertedTextUnderlineStyle:
aResult = NS_STYLE_TEXT_DECORATION_STYLE_DASHED;
break;
case eIntID_IMESelectedRawTextUnderlineStyle:
case eIntID_IMESelectedConvertedTextUnderline:
aResult = NS_STYLE_TEXT_DECORATION_STYLE_NONE;
break;
case eIntID_SpellCheckerUnderlineStyle:
aResult = NS_STYLE_TEXT_DECORATION_STYLE_WAVY;
break;
case eIntID_ScrollbarButtonAutoRepeatBehavior:
aResult = 0;
break;
case eIntID_SwipeAnimationEnabled:
aResult = 0;
break;
case eIntID_ColorPickerAvailable:
aResult = true;
break;
case eIntID_UseOverlayScrollbars:
aResult = false;
break;
case eIntID_AllowOverlayScrollbarsOverlap:
aResult = 0;
break;
case eIntID_ScrollbarDisplayOnMouseMove:
aResult = 1;
break;
case eIntID_ScrollbarFadeBeginDelay:
aResult = 2500;
break;
case eIntID_ScrollbarFadeDuration:
aResult = 350;
break;
case eIntID_ContextMenuOffsetVertical:
case eIntID_ContextMenuOffsetHorizontal:
aResult = 2;
break;
default:
aResult = 0;
res = NS_ERROR_FAILURE;
}
return res;
}
nsresult
nsLookAndFeel::GetFloatImpl(FloatID aID, float &aResult)
{
nsresult res = nsXPLookAndFeel::GetFloatImpl(aID, aResult);
if (NS_SUCCEEDED(res))
return res;
res = NS_OK;
switch (aID) {
case eFloatID_IMEUnderlineRelativeSize:
aResult = 1.0f;
break;
case eFloatID_SpellCheckerUnderlineRelativeSize:
aResult = 1.0f;
break;
default:
aResult = -1.0;
res = NS_ERROR_FAILURE;
}
return res;
}
static bool
GetSysFontInfo(HDC aHDC, LookAndFeel::FontID anID,
nsString &aFontName,
gfxFontStyle &aFontStyle)
{
LOGFONTW* ptrLogFont = nullptr;
LOGFONTW logFont;
NONCLIENTMETRICSW ncm;
char16_t name[LF_FACESIZE];
bool useShellDlg = false;
// Depending on which stock font we want, there are a couple of
// places we might have to look it up.
switch (anID) {
case LookAndFeel::eFont_Icon:
if (!::SystemParametersInfoW(SPI_GETICONTITLELOGFONT,
sizeof(logFont), (PVOID)&logFont, 0))
return false;
ptrLogFont = &logFont;
break;
default:
ncm.cbSize = sizeof(NONCLIENTMETRICSW);
if (!::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
sizeof(ncm), (PVOID)&ncm, 0))
return false;
switch (anID) {
case LookAndFeel::eFont_Menu:
case LookAndFeel::eFont_PullDownMenu:
ptrLogFont = &ncm.lfMenuFont;
break;
case LookAndFeel::eFont_Caption:
ptrLogFont = &ncm.lfCaptionFont;
break;
case LookAndFeel::eFont_SmallCaption:
ptrLogFont = &ncm.lfSmCaptionFont;
break;
case LookAndFeel::eFont_StatusBar:
case LookAndFeel::eFont_Tooltips:
ptrLogFont = &ncm.lfStatusFont;
break;
case LookAndFeel::eFont_Widget:
case LookAndFeel::eFont_Dialog:
case LookAndFeel::eFont_Button:
case LookAndFeel::eFont_Field:
case LookAndFeel::eFont_List:
// XXX It's not clear to me whether this is exactly the right
// set of LookAndFeel values to map to the dialog font; we may
// want to add or remove cases here after reviewing the visual
// results under various Windows versions.
useShellDlg = true;
// Fall through so that we can get size from lfMessageFont;
// but later we'll use the (virtual) "MS Shell Dlg 2" font name
// instead of the LOGFONT's.
default:
ptrLogFont = &ncm.lfMessageFont;
break;
}
break;
}
// Get scaling factor from physical to logical pixels
double pixelScale = 1.0 / WinUtils::SystemScaleFactor();
// The lfHeight is in pixels, and it needs to be adjusted for the
// device it will be displayed on.
// Screens and Printers will differ in DPI
//
// So this accounts for the difference in the DeviceContexts
// The pixelScale will typically be 1.0 for the screen
// (though larger for hi-dpi screens where the Windows resolution
// scale factor is 125% or 150% or even more), and could be
// any value when going to a printer, for example pixelScale is
// 6.25 when going to a 600dpi printer.
float pixelHeight = -ptrLogFont->lfHeight;
if (pixelHeight < 0) {
HFONT hFont = ::CreateFontIndirectW(ptrLogFont);
if (!hFont)
return false;
HGDIOBJ hObject = ::SelectObject(aHDC, hFont);
TEXTMETRIC tm;
::GetTextMetrics(aHDC, &tm);
::SelectObject(aHDC, hObject);
::DeleteObject(hFont);
pixelHeight = tm.tmAscent;
}
pixelHeight *= pixelScale;
// we have problem on Simplified Chinese system because the system
// report the default font size is 8 points. but if we use 8, the text
// display very ugly. force it to be at 9 points (12 pixels) on that
// system (cp936), but leave other sizes alone.
if (pixelHeight < 12 && ::GetACP() == 936)
pixelHeight = 12;
aFontStyle.size = pixelHeight;
// FIXME: What about oblique?
aFontStyle.style =
(ptrLogFont->lfItalic) ? NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL;
// FIXME: Other weights?
aFontStyle.weight =
(ptrLogFont->lfWeight == FW_BOLD ?
NS_FONT_WEIGHT_BOLD : NS_FONT_WEIGHT_NORMAL);
// FIXME: Set aFontStyle->stretch correctly!
aFontStyle.stretch = NS_FONT_STRETCH_NORMAL;
aFontStyle.systemFont = true;
if (useShellDlg) {
aFontName = NS_LITERAL_STRING("MS Shell Dlg 2");
} else {
memcpy(name, ptrLogFont->lfFaceName, LF_FACESIZE*sizeof(char16_t));
aFontName = name;
}
return true;
}
bool
nsLookAndFeel::GetFontImpl(FontID anID, nsString &aFontName,
gfxFontStyle &aFontStyle,
float aDevPixPerCSSPixel)
{
HDC tdc = GetDC(nullptr);
bool status = GetSysFontInfo(tdc, anID, aFontName, aFontStyle);
ReleaseDC(nullptr, tdc);
// now convert the logical font size from GetSysFontInfo into device pixels for layout
aFontStyle.size *= aDevPixPerCSSPixel;
return status;
}
/* virtual */
char16_t
nsLookAndFeel::GetPasswordCharacterImpl()
{
#define UNICODE_BLACK_CIRCLE_CHAR 0x25cf
return UNICODE_BLACK_CIRCLE_CHAR;
}
nsTArray<LookAndFeelInt>
nsLookAndFeel::GetIntCacheImpl()
{
nsTArray<LookAndFeelInt> lookAndFeelIntCache =
nsXPLookAndFeel::GetIntCacheImpl();
LookAndFeelInt useAccessibilityTheme;
useAccessibilityTheme.id = eIntID_UseAccessibilityTheme;
useAccessibilityTheme.value = GetInt(eIntID_UseAccessibilityTheme);
lookAndFeelIntCache.AppendElement(useAccessibilityTheme);
return lookAndFeelIntCache;
}
void
nsLookAndFeel::SetIntCacheImpl(const nsTArray<LookAndFeelInt>& aLookAndFeelIntCache)
{
for (auto entry : aLookAndFeelIntCache) {
if (entry.id == eIntID_UseAccessibilityTheme) {
mUseAccessibilityTheme = entry.value;
break;
}
}
}

View file

@ -0,0 +1,65 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __nsLookAndFeel
#define __nsLookAndFeel
#include "nsXPLookAndFeel.h"
/*
* Gesture System Metrics
*/
#ifndef SM_DIGITIZER
#define SM_DIGITIZER 94
#define TABLET_CONFIG_NONE 0x00000000
#define NID_INTEGRATED_TOUCH 0x00000001
#define NID_EXTERNAL_TOUCH 0x00000002
#define NID_INTEGRATED_PEN 0x00000004
#define NID_EXTERNAL_PEN 0x00000008
#define NID_MULTI_INPUT 0x00000040
#define NID_READY 0x00000080
#endif
/*
* Tablet mode detection
*/
#ifndef SM_SYSTEMDOCKED
#define SM_CONVERTIBLESLATEMODE 0x00002003
#define SM_SYSTEMDOCKED 0x00002004
typedef enum _AR_STATE
{
AR_ENABLED = 0x0,
AR_DISABLED = 0x1,
AR_SUPPRESSED = 0x2,
AR_REMOTESESSION = 0x4,
AR_MULTIMON = 0x8,
AR_NOSENSOR = 0x10,
AR_NOT_SUPPORTED = 0x20,
AR_DOCKED = 0x40,
AR_LAPTOP = 0x80
} AR_STATE, *PAR_STATE;
#endif
class nsLookAndFeel: public nsXPLookAndFeel {
static OperatingSystemVersion GetOperatingSystemVersion();
public:
nsLookAndFeel();
virtual ~nsLookAndFeel();
virtual nsresult NativeGetColor(ColorID aID, nscolor &aResult);
virtual nsresult GetIntImpl(IntID aID, int32_t &aResult);
virtual nsresult GetFloatImpl(FloatID aID, float &aResult);
virtual bool GetFontImpl(FontID aID, nsString& aFontName,
gfxFontStyle& aFontStyle,
float aDevPixPerCSSPixel);
virtual char16_t GetPasswordCharacterImpl();
virtual nsTArray<LookAndFeelInt> GetIntCacheImpl();
virtual void SetIntCacheImpl(const nsTArray<LookAndFeelInt>& aLookAndFeelIntCache);
private:
int32_t mUseAccessibilityTheme;
};
#endif

View file

@ -0,0 +1,109 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsNativeDragSource.h"
#include <stdio.h>
#include "nsISupportsImpl.h"
#include "nsString.h"
#include "nsIServiceManager.h"
#include "nsToolkit.h"
#include "nsWidgetsCID.h"
#include "nsIDragService.h"
/*
* class nsNativeDragSource
*/
nsNativeDragSource::nsNativeDragSource(nsIDOMDataTransfer* aDataTransfer) :
m_cRef(0),
m_hCursor(nullptr),
mUserCancelled(false)
{
mDataTransfer = do_QueryInterface(aDataTransfer);
}
nsNativeDragSource::~nsNativeDragSource()
{
}
STDMETHODIMP
nsNativeDragSource::QueryInterface(REFIID riid, void** ppv)
{
*ppv=nullptr;
if (IID_IUnknown==riid || IID_IDropSource==riid)
*ppv=this;
if (nullptr!=*ppv) {
((LPUNKNOWN)*ppv)->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG)
nsNativeDragSource::AddRef(void)
{
++m_cRef;
NS_LOG_ADDREF(this, m_cRef, "nsNativeDragSource", sizeof(*this));
return m_cRef;
}
STDMETHODIMP_(ULONG)
nsNativeDragSource::Release(void)
{
--m_cRef;
NS_LOG_RELEASE(this, m_cRef, "nsNativeDragSource");
if (0 != m_cRef)
return m_cRef;
delete this;
return 0;
}
STDMETHODIMP
nsNativeDragSource::QueryContinueDrag(BOOL fEsc, DWORD grfKeyState)
{
static NS_DEFINE_IID(kCDragServiceCID, NS_DRAGSERVICE_CID);
nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
if (dragService) {
DWORD pos = ::GetMessagePos();
dragService->DragMoved(GET_X_LPARAM(pos), GET_Y_LPARAM(pos));
}
if (fEsc) {
mUserCancelled = true;
return DRAGDROP_S_CANCEL;
}
if (!(grfKeyState & MK_LBUTTON) || (grfKeyState & MK_RBUTTON))
return DRAGDROP_S_DROP;
return S_OK;
}
STDMETHODIMP
nsNativeDragSource::GiveFeedback(DWORD dwEffect)
{
// For drags involving tabs, we do some custom work with cursors.
if (mDataTransfer) {
nsAutoString cursor;
mDataTransfer->GetMozCursor(cursor);
if (cursor.EqualsLiteral("default")) {
m_hCursor = ::LoadCursor(0, IDC_ARROW);
} else {
m_hCursor = nullptr;
}
}
if (m_hCursor) {
::SetCursor(m_hCursor);
return S_OK;
}
// Let the system choose which cursor to apply.
return DRAGDROP_S_USEDEFAULTCURSORS;
}

View file

@ -0,0 +1,66 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _nsNativeDragSource_h_
#define _nsNativeDragSource_h_
#include "nscore.h"
#include "nsIDOMDataTransfer.h"
#include "nsCOMPtr.h"
#include <ole2.h>
#include <oleidl.h>
#include "mozilla/Attributes.h"
//class nsIDragSource;
/*
* nsNativeDragSource implements the IDropSource interface and gets
* most of its behavior from the associated adapter (m_dragDrop).
*/
class nsNativeDragSource final : public IDropSource
{
public:
// construct an nsNativeDragSource referencing adapter
// nsNativeDragSource(nsIDragSource * adapter);
nsNativeDragSource(nsIDOMDataTransfer* aDataTransfer);
~nsNativeDragSource();
// IUnknown methods - see iunknown.h for documentation
STDMETHODIMP QueryInterface(REFIID, void**);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// IDropSource methods - see idropsrc.h for documentation
// Return DRAGDROP_S_USEDEFAULTCURSORS if this object lets OLE provide
// default cursors, otherwise return NOERROR. This method gets called in
// response to changes that the target makes to dEffect (DragEnter,
// DragOver).
STDMETHODIMP GiveFeedback(DWORD dEffect);
// This method gets called if there is any change in the mouse or key
// state. Return DRAGDROP_S_CANCEL to stop the drag, DRAGDROP_S_DROP
// to execute the drop, otherwise NOERROR.
STDMETHODIMP QueryContinueDrag(BOOL fESC, DWORD grfKeyState);
bool UserCancelled() { return mUserCancelled; }
protected:
// Reference count
ULONG m_cRef;
// Data object, hold information about cursor state
nsCOMPtr<nsIDOMDataTransfer> mDataTransfer;
// Custom drag cursor
HCURSOR m_hCursor;
// true if the user cancelled the drag by pressing escape
bool mUserCancelled;
};
#endif // _nsNativeDragSource_h_

View file

@ -0,0 +1,486 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <stdio.h>
#include "nsIDragService.h"
#include "nsWidgetsCID.h"
#include "nsNativeDragTarget.h"
#include "nsDragService.h"
#include "nsIServiceManager.h"
#include "nsIDOMNode.h"
#include "nsCOMPtr.h"
#include "nsIWidget.h"
#include "nsWindow.h"
#include "nsClipboard.h"
#include "KeyboardLayout.h"
#include "mozilla/MouseEvents.h"
using namespace mozilla;
using namespace mozilla::widget;
/* Define Interface IDs */
static NS_DEFINE_IID(kIDragServiceIID, NS_IDRAGSERVICE_IID);
// This is cached for Leave notification
static POINTL gDragLastPoint;
/*
* class nsNativeDragTarget
*/
nsNativeDragTarget::nsNativeDragTarget(nsIWidget * aWidget)
: m_cRef(0),
mEffectsAllowed(DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK),
mEffectsPreferred(DROPEFFECT_NONE),
mTookOwnRef(false), mWidget(aWidget), mDropTargetHelper(nullptr)
{
static NS_DEFINE_IID(kCDragServiceCID, NS_DRAGSERVICE_CID);
mHWnd = (HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW);
/*
* Create/Get the DragService that we have implemented
*/
CallGetService(kCDragServiceCID, &mDragService);
}
nsNativeDragTarget::~nsNativeDragTarget()
{
NS_RELEASE(mDragService);
if (mDropTargetHelper) {
mDropTargetHelper->Release();
mDropTargetHelper = nullptr;
}
}
// IUnknown methods - see iunknown.h for documentation
STDMETHODIMP
nsNativeDragTarget::QueryInterface(REFIID riid, void** ppv)
{
*ppv=nullptr;
if (IID_IUnknown == riid || IID_IDropTarget == riid)
*ppv=this;
if (nullptr!=*ppv) {
((LPUNKNOWN)*ppv)->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG)
nsNativeDragTarget::AddRef(void)
{
++m_cRef;
NS_LOG_ADDREF(this, m_cRef, "nsNativeDragTarget", sizeof(*this));
return m_cRef;
}
STDMETHODIMP_(ULONG) nsNativeDragTarget::Release(void)
{
--m_cRef;
NS_LOG_RELEASE(this, m_cRef, "nsNativeDragTarget");
if (0 != m_cRef)
return m_cRef;
delete this;
return 0;
}
void
nsNativeDragTarget::GetGeckoDragAction(DWORD grfKeyState, LPDWORD pdwEffect,
uint32_t * aGeckoAction)
{
// If a window is disabled or a modal window is on top of it
// (which implies it is disabled), then we should not allow dropping.
if (!mWidget->IsEnabled()) {
*pdwEffect = DROPEFFECT_NONE;
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_NONE;
return;
}
// If the user explicitly uses a modifier key, they want the associated action
// Shift + Control -> LINK, Shift -> MOVE, Ctrl -> COPY
DWORD desiredEffect = DROPEFFECT_NONE;
if ((grfKeyState & MK_CONTROL) && (grfKeyState & MK_SHIFT)) {
desiredEffect = DROPEFFECT_LINK;
} else if (grfKeyState & MK_SHIFT) {
desiredEffect = DROPEFFECT_MOVE;
} else if (grfKeyState & MK_CONTROL) {
desiredEffect = DROPEFFECT_COPY;
}
// Determine the desired effect from what is allowed and preferred.
if (!(desiredEffect &= mEffectsAllowed)) {
// No modifier key effect is set which is also allowed, check
// the preference of the data.
desiredEffect = mEffectsPreferred & mEffectsAllowed;
if (!desiredEffect) {
// No preference is set, so just fall back to the allowed effect itself
desiredEffect = mEffectsAllowed;
}
}
// Otherwise we should specify the first available effect
// from MOVE, COPY, or LINK.
if (desiredEffect & DROPEFFECT_MOVE) {
*pdwEffect = DROPEFFECT_MOVE;
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_MOVE;
} else if (desiredEffect & DROPEFFECT_COPY) {
*pdwEffect = DROPEFFECT_COPY;
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_COPY;
} else if (desiredEffect & DROPEFFECT_LINK) {
*pdwEffect = DROPEFFECT_LINK;
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_LINK;
} else {
*pdwEffect = DROPEFFECT_NONE;
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_NONE;
}
}
inline
bool
IsKeyDown(char key)
{
return GetKeyState(key) < 0;
}
void
nsNativeDragTarget::DispatchDragDropEvent(EventMessage aEventMessage,
const POINTL& aPT)
{
nsEventStatus status;
WidgetDragEvent event(true, aEventMessage, mWidget);
nsWindow * win = static_cast<nsWindow *>(mWidget);
win->InitEvent(event);
POINT cpos;
cpos.x = aPT.x;
cpos.y = aPT.y;
if (mHWnd != nullptr) {
::ScreenToClient(mHWnd, &cpos);
event.mRefPoint = LayoutDeviceIntPoint(cpos.x, cpos.y);
} else {
event.mRefPoint = LayoutDeviceIntPoint(0, 0);
}
ModifierKeyState modifierKeyState;
modifierKeyState.InitInputEvent(event);
event.inputSource = static_cast<nsBaseDragService*>(mDragService)->GetInputSource();
mWidget->DispatchEvent(&event, status);
}
void
nsNativeDragTarget::ProcessDrag(EventMessage aEventMessage,
DWORD grfKeyState,
POINTL ptl,
DWORD* pdwEffect)
{
// Before dispatching the event make sure we have the correct drop action set
uint32_t geckoAction;
GetGeckoDragAction(grfKeyState, pdwEffect, &geckoAction);
// Set the current action into the Gecko specific type
nsCOMPtr<nsIDragSession> currSession;
mDragService->GetCurrentSession(getter_AddRefs(currSession));
if (!currSession) {
return;
}
currSession->SetDragAction(geckoAction);
// Dispatch the event into Gecko
DispatchDragDropEvent(aEventMessage, ptl);
// If TakeChildProcessDragAction returns something other than
// DRAGDROP_ACTION_UNINITIALIZED, it means that the last event was sent
// to the child process and this event is also being sent to the child
// process. In this case, use the last event's action instead.
nsDragService* dragService = static_cast<nsDragService *>(mDragService);
currSession->GetDragAction(&geckoAction);
int32_t childDragAction = dragService->TakeChildProcessDragAction();
if (childDragAction != nsIDragService::DRAGDROP_ACTION_UNINITIALIZED) {
geckoAction = childDragAction;
}
if (nsIDragService::DRAGDROP_ACTION_LINK & geckoAction) {
*pdwEffect = DROPEFFECT_LINK;
}
else if (nsIDragService::DRAGDROP_ACTION_COPY & geckoAction) {
*pdwEffect = DROPEFFECT_COPY;
}
else if (nsIDragService::DRAGDROP_ACTION_MOVE & geckoAction) {
*pdwEffect = DROPEFFECT_MOVE;
}
else {
*pdwEffect = DROPEFFECT_NONE;
}
if (aEventMessage != eDrop) {
// Get the cached drag effect from the drag service, the data member should
// have been set by whoever handled the WidgetGUIEvent or nsIDOMEvent on
// drags.
bool canDrop;
currSession->GetCanDrop(&canDrop);
if (!canDrop) {
*pdwEffect = DROPEFFECT_NONE;
}
}
// Clear the cached value
currSession->SetCanDrop(false);
}
// IDropTarget methods
STDMETHODIMP
nsNativeDragTarget::DragEnter(LPDATAOBJECT pIDataSource,
DWORD grfKeyState,
POINTL ptl,
DWORD* pdwEffect)
{
if (!mDragService) {
return E_FAIL;
}
mEffectsAllowed = *pdwEffect;
AddLinkSupportIfCanBeGenerated(pIDataSource);
// Drag and drop image helper
if (GetDropTargetHelper()) {
POINT pt = { ptl.x, ptl.y };
GetDropTargetHelper()->DragEnter(mHWnd, pIDataSource, &pt, *pdwEffect);
}
// save a ref to this, in case the window is destroyed underneath us
NS_ASSERTION(!mTookOwnRef, "own ref already taken!");
this->AddRef();
mTookOwnRef = true;
// tell the drag service about this drag (it may have come from an
// outside app).
mDragService->StartDragSession();
void* tempOutData = nullptr;
uint32_t tempDataLen = 0;
nsresult loadResult = nsClipboard::GetNativeDataOffClipboard(
pIDataSource, 0, ::RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT), nullptr, &tempOutData, &tempDataLen);
if (NS_SUCCEEDED(loadResult) && tempOutData) {
mEffectsPreferred = *((DWORD*)tempOutData);
free(tempOutData);
} else {
// We have no preference if we can't obtain it
mEffectsPreferred = DROPEFFECT_NONE;
}
// Set the native data object into drag service
//
// This cast is ok because in the constructor we created a
// the actual implementation we wanted, so we know this is
// a nsDragService. It should be a private interface, though.
nsDragService * winDragService =
static_cast<nsDragService *>(mDragService);
winDragService->SetIDataObject(pIDataSource);
// Now process the native drag state and then dispatch the event
ProcessDrag(eDragEnter, grfKeyState, ptl, pdwEffect);
return S_OK;
}
void
nsNativeDragTarget::AddLinkSupportIfCanBeGenerated(LPDATAOBJECT aIDataSource)
{
// If we don't have a link effect, but we can generate one, fix the
// drop effect to include it.
if (!(mEffectsAllowed & DROPEFFECT_LINK) && aIDataSource) {
if (S_OK == ::OleQueryLinkFromData(aIDataSource)) {
mEffectsAllowed |= DROPEFFECT_LINK;
}
}
}
STDMETHODIMP
nsNativeDragTarget::DragOver(DWORD grfKeyState,
POINTL ptl,
LPDWORD pdwEffect)
{
if (!mDragService) {
return E_FAIL;
}
// If a LINK effect could be generated previously from a DragEnter(),
// then we should include it as an allowed effect.
mEffectsAllowed = (*pdwEffect) | (mEffectsAllowed & DROPEFFECT_LINK);
nsCOMPtr<nsIDragSession> currentDragSession;
mDragService->GetCurrentSession(getter_AddRefs(currentDragSession));
if (!currentDragSession) {
return S_OK; // Drag was canceled.
}
// without the AddRef() |this| can get destroyed in an event handler
this->AddRef();
// Drag and drop image helper
if (GetDropTargetHelper()) {
POINT pt = { ptl.x, ptl.y };
GetDropTargetHelper()->DragOver(&pt, *pdwEffect);
}
mDragService->FireDragEventAtSource(eDrag);
// Now process the native drag state and then dispatch the event
ProcessDrag(eDragOver, grfKeyState, ptl, pdwEffect);
this->Release();
return S_OK;
}
STDMETHODIMP
nsNativeDragTarget::DragLeave()
{
if (!mDragService) {
return E_FAIL;
}
// Drag and drop image helper
if (GetDropTargetHelper()) {
GetDropTargetHelper()->DragLeave();
}
// dispatch the event into Gecko
DispatchDragDropEvent(eDragExit, gDragLastPoint);
nsCOMPtr<nsIDragSession> currentDragSession;
mDragService->GetCurrentSession(getter_AddRefs(currentDragSession));
if (currentDragSession) {
nsCOMPtr<nsIDOMNode> sourceNode;
currentDragSession->GetSourceNode(getter_AddRefs(sourceNode));
if (!sourceNode) {
// We're leaving a window while doing a drag that was
// initiated in a different app. End the drag session, since
// we're done with it for now (until the user drags back into
// mozilla).
mDragService->EndDragSession(false);
}
}
// release the ref that was taken in DragEnter
NS_ASSERTION(mTookOwnRef, "want to release own ref, but not taken!");
if (mTookOwnRef) {
this->Release();
mTookOwnRef = false;
}
return S_OK;
}
void
nsNativeDragTarget::DragCancel()
{
// Cancel the drag session if we did DragEnter.
if (mTookOwnRef) {
if (GetDropTargetHelper()) {
GetDropTargetHelper()->DragLeave();
}
if (mDragService) {
mDragService->EndDragSession(false);
}
this->Release(); // matching the AddRef in DragEnter
mTookOwnRef = false;
}
}
STDMETHODIMP
nsNativeDragTarget::Drop(LPDATAOBJECT pData,
DWORD grfKeyState,
POINTL aPT,
LPDWORD pdwEffect)
{
if (!mDragService) {
return E_FAIL;
}
mEffectsAllowed = *pdwEffect;
AddLinkSupportIfCanBeGenerated(pData);
// Drag and drop image helper
if (GetDropTargetHelper()) {
POINT pt = { aPT.x, aPT.y };
GetDropTargetHelper()->Drop(pData, &pt, *pdwEffect);
}
// Set the native data object into the drag service
//
// This cast is ok because in the constructor we created a
// the actual implementation we wanted, so we know this is
// a nsDragService (but it should still be a private interface)
nsDragService* winDragService = static_cast<nsDragService*>(mDragService);
winDragService->SetIDataObject(pData);
// NOTE: ProcessDrag spins the event loop which may destroy arbitrary objects.
// We use strong refs to prevent it from destroying these:
RefPtr<nsNativeDragTarget> kungFuDeathGrip = this;
nsCOMPtr<nsIDragService> serv = mDragService;
// Now process the native drag state and then dispatch the event
ProcessDrag(eDrop, grfKeyState, aPT, pdwEffect);
nsCOMPtr<nsIDragSession> currentDragSession;
serv->GetCurrentSession(getter_AddRefs(currentDragSession));
if (!currentDragSession) {
return S_OK; // DragCancel() was called.
}
// Let the win drag service know whether this session experienced
// a drop event within the application. Drop will not oocur if the
// drop landed outside the app. (used in tab tear off, bug 455884)
winDragService->SetDroppedLocal();
// tell the drag service we're done with the session
// Use GetMessagePos to get the position of the mouse at the last message
// seen by the event loop. (Bug 489729)
DWORD pos = ::GetMessagePos();
POINT cpos;
cpos.x = GET_X_LPARAM(pos);
cpos.y = GET_Y_LPARAM(pos);
winDragService->SetDragEndPoint(nsIntPoint(cpos.x, cpos.y));
serv->EndDragSession(true);
// release the ref that was taken in DragEnter
NS_ASSERTION(mTookOwnRef, "want to release own ref, but not taken!");
if (mTookOwnRef) {
this->Release();
mTookOwnRef = false;
}
return S_OK;
}
/**
* By lazy loading mDropTargetHelper we save 50-70ms of startup time
* which is ~5% of startup time.
*/
IDropTargetHelper*
nsNativeDragTarget::GetDropTargetHelper()
{
if (!mDropTargetHelper) {
CoCreateInstance(CLSID_DragDropHelper, nullptr, CLSCTX_INPROC_SERVER,
IID_IDropTargetHelper, (LPVOID*)&mDropTargetHelper);
}
return mDropTargetHelper;
}

View file

@ -0,0 +1,102 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _nsNativeDragTarget_h_
#define _nsNativeDragTarget_h_
#include "nsCOMPtr.h"
#include "nsIDragSession.h"
#include <ole2.h>
#include <shlobj.h>
#ifndef IDropTargetHelper
#include <shobjidl.h> // Vista drag image interfaces
#undef LogSeverity // SetupAPI.h #defines this as DWORD
#endif
#include "mozilla/Attributes.h"
#include "mozilla/EventForwards.h"
class nsIDragService;
class nsIWidget;
/*
* nsNativeDragTarget implements the IDropTarget interface and gets most of its
* behavior from the associated adapter (m_dragDrop).
*/
class nsNativeDragTarget final : public IDropTarget
{
public:
nsNativeDragTarget(nsIWidget * aWidget);
~nsNativeDragTarget();
// IUnknown members - see iunknown.h for documentation
STDMETHODIMP QueryInterface(REFIID, void**);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// IDataTarget members
// Set pEffect based on whether this object can support a drop based on
// the data available from pSource, the key and mouse states specified
// in grfKeyState, and the coordinates specified by point. This is
// called by OLE when a drag enters this object's window (as registered
// by Initialize).
STDMETHODIMP DragEnter(LPDATAOBJECT pSource, DWORD grfKeyState,
POINTL point, DWORD* pEffect);
// Similar to DragEnter except it is called frequently while the drag
// is over this object's window.
STDMETHODIMP DragOver(DWORD grfKeyState, POINTL point, DWORD* pEffect);
// Release the drag-drop source and put internal state back to the point
// before the call to DragEnter. This is called when the drag leaves
// without a drop occurring.
STDMETHODIMP DragLeave();
// If point is within our region of interest and pSource's data supports
// one of our formats, get the data and set pEffect according to
// grfKeyState (DROPEFFECT_MOVE if the control key was not pressed,
// DROPEFFECT_COPY if the control key was pressed). Otherwise return
// E_FAIL.
STDMETHODIMP Drop(LPDATAOBJECT pSource, DWORD grfKeyState,
POINTL point, DWORD* pEffect);
/**
* Cancel the current drag session, if any.
*/
void DragCancel();
protected:
void GetGeckoDragAction(DWORD grfKeyState, LPDWORD pdwEffect,
uint32_t * aGeckoAction);
void ProcessDrag(mozilla::EventMessage aEventMessage, DWORD grfKeyState,
POINTL pt, DWORD* pdwEffect);
void DispatchDragDropEvent(mozilla::EventMessage aEventMessage,
const POINTL& aPT);
void AddLinkSupportIfCanBeGenerated(LPDATAOBJECT aIDataSource);
// Native Stuff
ULONG m_cRef; // reference count
HWND mHWnd;
DWORD mEffectsAllowed;
DWORD mEffectsPreferred;
bool mTookOwnRef;
// Gecko Stuff
nsIWidget * mWidget;
nsIDragService * mDragService;
// Drag target helper
IDropTargetHelper * GetDropTargetHelper();
private:
// Drag target helper
IDropTargetHelper * mDropTargetHelper;
};
#endif // _nsNativeDragTarget_h_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,128 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsNativeThemeWin_h
#define nsNativeThemeWin_h
#include "nsITheme.h"
#include "nsCOMPtr.h"
#include "nsIAtom.h"
#include "nsNativeTheme.h"
#include "gfxTypes.h"
#include <windows.h>
#include "mozilla/TimeStamp.h"
#include "nsSize.h"
class nsNativeThemeWin : private nsNativeTheme,
public nsITheme {
virtual ~nsNativeThemeWin();
public:
typedef mozilla::TimeStamp TimeStamp;
typedef mozilla::TimeDuration TimeDuration;
NS_DECL_ISUPPORTS_INHERITED
// The nsITheme interface.
NS_IMETHOD DrawWidgetBackground(nsRenderingContext* aContext,
nsIFrame* aFrame,
uint8_t aWidgetType,
const nsRect& aRect,
const nsRect& aDirtyRect) override;
NS_IMETHOD GetWidgetBorder(nsDeviceContext* aContext,
nsIFrame* aFrame,
uint8_t aWidgetType,
nsIntMargin* aResult) override;
virtual bool GetWidgetPadding(nsDeviceContext* aContext,
nsIFrame* aFrame,
uint8_t aWidgetType,
nsIntMargin* aResult) override;
virtual bool GetWidgetOverflow(nsDeviceContext* aContext,
nsIFrame* aFrame,
uint8_t aWidgetType,
nsRect* aOverflowRect) override;
NS_IMETHOD GetMinimumWidgetSize(nsPresContext* aPresContext, nsIFrame* aFrame,
uint8_t aWidgetType,
mozilla::LayoutDeviceIntSize* aResult,
bool* aIsOverridable) override;
virtual Transparency GetWidgetTransparency(nsIFrame* aFrame, uint8_t aWidgetType) override;
NS_IMETHOD WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType,
nsIAtom* aAttribute, bool* aShouldRepaint,
const nsAttrValue* aOldValue) override;
NS_IMETHOD ThemeChanged() override;
bool ThemeSupportsWidget(nsPresContext* aPresContext,
nsIFrame* aFrame,
uint8_t aWidgetType) override;
bool WidgetIsContainer(uint8_t aWidgetType) override;
bool ThemeDrawsFocusForWidget(uint8_t aWidgetType) override;
bool ThemeNeedsComboboxDropmarker() override;
virtual bool WidgetAppearanceDependsOnWindowFocus(uint8_t aWidgetType) override;
enum {
eThemeGeometryTypeWindowButtons = eThemeGeometryTypeUnknown + 1
};
virtual ThemeGeometryType ThemeGeometryTypeForWidget(nsIFrame* aFrame,
uint8_t aWidgetType) override;
virtual bool ShouldHideScrollbars() override;
nsNativeThemeWin();
protected:
HANDLE GetTheme(uint8_t aWidgetType);
nsresult GetThemePartAndState(nsIFrame* aFrame, uint8_t aWidgetType,
int32_t& aPart, int32_t& aState);
nsresult ClassicGetThemePartAndState(nsIFrame* aFrame, uint8_t aWidgetType,
int32_t& aPart, int32_t& aState, bool& aFocused);
nsresult ClassicDrawWidgetBackground(nsRenderingContext* aContext,
nsIFrame* aFrame,
uint8_t aWidgetType,
const nsRect& aRect,
const nsRect& aClipRect);
nsresult ClassicGetWidgetBorder(nsDeviceContext* aContext,
nsIFrame* aFrame,
uint8_t aWidgetType,
nsIntMargin* aResult);
bool ClassicGetWidgetPadding(nsDeviceContext* aContext,
nsIFrame* aFrame,
uint8_t aWidgetType,
nsIntMargin* aResult);
nsresult ClassicGetMinimumWidgetSize(nsIFrame* aFrame, uint8_t aWidgetType,
mozilla::LayoutDeviceIntSize* aResult,
bool* aIsOverridable);
bool ClassicThemeSupportsWidget(nsIFrame* aFrame, uint8_t aWidgetType);
void DrawCheckedRect(HDC hdc, const RECT& rc, int32_t fore, int32_t back,
HBRUSH defaultBack);
uint32_t GetWidgetNativeDrawingFlags(uint8_t aWidgetType);
int32_t StandardGetState(nsIFrame* aFrame, uint8_t aWidgetType, bool wantFocused);
bool IsMenuActive(nsIFrame* aFrame, uint8_t aWidgetType);
RECT CalculateProgressOverlayRect(nsIFrame* aFrame, RECT* aWidgetRect,
bool aIsVertical, bool aIsIndeterminate,
bool aIsClassic);
void DrawThemedProgressMeter(nsIFrame* aFrame, int aWidgetType,
HANDLE aTheme, HDC aHdc,
int aPart, int aState,
RECT* aWidgetRect, RECT* aClipRect,
gfxFloat aAppUnits);
private:
TimeStamp mProgressDeterminateTimeStamp;
TimeStamp mProgressIndeterminateTimeStamp;
};
#endif

View file

@ -0,0 +1,162 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsCOMPtr.h"
#include "nsPrintOptionsWin.h"
#include "nsPrintSettingsWin.h"
#include "nsPrintDialogUtil.h"
#include "nsGfxCIID.h"
#include "nsIServiceManager.h"
#include "nsIWebBrowserPrint.h"
#include "nsWindowsHelpers.h"
#include "ipc/IPCMessageUtils.h"
const char kPrinterEnumeratorContractID[] = "@mozilla.org/gfx/printerenumerator;1";
using namespace mozilla::embedding;
/** ---------------------------------------------------
* See documentation in nsPrintOptionsWin.h
* @update 6/21/00 dwc
*/
nsPrintOptionsWin::nsPrintOptionsWin()
{
}
/** ---------------------------------------------------
* See documentation in nsPrintOptionsImpl.h
* @update 6/21/00 dwc
*/
nsPrintOptionsWin::~nsPrintOptionsWin()
{
}
NS_IMETHODIMP
nsPrintOptionsWin::SerializeToPrintData(nsIPrintSettings* aSettings,
nsIWebBrowserPrint* aWBP,
PrintData* data)
{
nsresult rv = nsPrintOptions::SerializeToPrintData(aSettings, aWBP, data);
NS_ENSURE_SUCCESS(rv, rv);
// Windows wants this information for its print dialogs
if (aWBP) {
aWBP->GetIsFramesetDocument(&data->isFramesetDocument());
aWBP->GetIsFramesetFrameSelected(&data->isFramesetFrameSelected());
aWBP->GetIsIFrameSelected(&data->isIFrameSelected());
aWBP->GetIsRangeSelection(&data->isRangeSelection());
}
nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aSettings);
if (!psWin) {
return NS_ERROR_FAILURE;
}
char16_t* deviceName;
char16_t* driverName;
psWin->GetDeviceName(&deviceName);
psWin->GetDriverName(&driverName);
data->deviceName().Assign(deviceName);
data->driverName().Assign(driverName);
free(deviceName);
free(driverName);
// When creating the print dialog on Windows, we only need to send certain
// print settings information from the parent to the child not vice versa.
if (XRE_IsParentProcess()) {
psWin->GetPrintableWidthInInches(&data->printableWidthInInches());
psWin->GetPrintableHeightInInches(&data->printableHeightInInches());
// A DEVMODE can actually be of arbitrary size. If it turns out that it'll
// make our IPC message larger than the limit, then we'll error out.
LPDEVMODEW devModeRaw;
psWin->GetDevMode(&devModeRaw); // This actually allocates a copy of the
// the nsIPrintSettingsWin DEVMODE, so
// we're now responsible for deallocating
// it. We'll use an nsAutoDevMode helper
// to do this.
if (devModeRaw) {
nsAutoDevMode devMode(devModeRaw);
devModeRaw = nullptr;
size_t devModeTotalSize = devMode->dmSize + devMode->dmDriverExtra;
size_t msgTotalSize = sizeof(PrintData) + devModeTotalSize;
if (msgTotalSize > IPC::MAX_MESSAGE_SIZE) {
return NS_ERROR_FAILURE;
}
// Instead of reaching in and manually reading each member, we'll just
// copy the bits over.
const char* devModeData = reinterpret_cast<const char*>(devMode.get());
nsTArray<uint8_t> arrayBuf;
arrayBuf.AppendElements(devModeData, devModeTotalSize);
data->devModeData().SwapElements(arrayBuf);
}
}
return NS_OK;
}
NS_IMETHODIMP
nsPrintOptionsWin::DeserializeToPrintSettings(const PrintData& data,
nsIPrintSettings* settings)
{
nsresult rv = nsPrintOptions::DeserializeToPrintSettings(data, settings);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(settings);
if (!settings) {
return NS_ERROR_FAILURE;
}
if (XRE_IsContentProcess()) {
psWin->SetDeviceName(data.deviceName().get());
psWin->SetDriverName(data.driverName().get());
psWin->SetPrintableWidthInInches(data.printableWidthInInches());
psWin->SetPrintableHeightInInches(data.printableHeightInInches());
if (data.devModeData().IsEmpty()) {
psWin->SetDevMode(nullptr);
} else {
// Check minimum length of DEVMODE data.
auto devModeDataLength = data.devModeData().Length();
if (devModeDataLength < sizeof(DEVMODEW)) {
NS_WARNING("DEVMODE data is too short.");
return NS_ERROR_FAILURE;
}
DEVMODEW* devMode = reinterpret_cast<DEVMODEW*>(
const_cast<uint8_t*>(data.devModeData().Elements()));
// Check actual length of DEVMODE data.
if ((devMode->dmSize + devMode->dmDriverExtra) != devModeDataLength) {
NS_WARNING("DEVMODE length is incorrect.");
return NS_ERROR_FAILURE;
}
psWin->SetDevMode(devMode); // Copies
}
}
return NS_OK;
}
nsresult nsPrintOptionsWin::_CreatePrintSettings(nsIPrintSettings **_retval)
{
*_retval = nullptr;
nsPrintSettingsWin* printSettings = new nsPrintSettingsWin(); // does not initially ref count
NS_ENSURE_TRUE(printSettings, NS_ERROR_OUT_OF_MEMORY);
NS_ADDREF(*_retval = printSettings); // ref count
return NS_OK;
}

View file

@ -0,0 +1,36 @@
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsPrintOptionsWin_h__
#define nsPrintOptionsWin_h__
#include "mozilla/embedding/PPrinting.h"
#include "nsPrintOptionsImpl.h"
class nsIPrintSettings;
class nsIWebBrowserPrint;
//*****************************************************************************
//*** nsPrintOptions
//*****************************************************************************
class nsPrintOptionsWin : public nsPrintOptions
{
public:
nsPrintOptionsWin();
virtual ~nsPrintOptionsWin();
NS_IMETHODIMP SerializeToPrintData(nsIPrintSettings* aSettings,
nsIWebBrowserPrint* aWBP,
mozilla::embedding::PrintData* data);
NS_IMETHODIMP DeserializeToPrintSettings(const mozilla::embedding::PrintData& data,
nsIPrintSettings* settings);
virtual nsresult _CreatePrintSettings(nsIPrintSettings **_retval);
};
#endif /* nsPrintOptions_h__ */

View file

@ -0,0 +1,528 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsPrintSettingsWin.h"
#include "mozilla/ArrayUtils.h"
#include "nsCRT.h"
// Using paper sizes from wingdi.h and the units given there, plus a little
// extra research for the ones it doesn't give. Looks like the list hasn't
// changed since Windows 2000, so should be fairly stable now.
const short kPaperSizeUnits[] = {
nsIPrintSettings::kPaperSizeMillimeters, // Not Used default to mm as DEVMODE
// uses tenths of mm, just in case
nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTER
nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTERSMALL
nsIPrintSettings::kPaperSizeInches, // DMPAPER_TABLOID
nsIPrintSettings::kPaperSizeInches, // DMPAPER_LEDGER
nsIPrintSettings::kPaperSizeInches, // DMPAPER_LEGAL
nsIPrintSettings::kPaperSizeInches, // DMPAPER_STATEMENT
nsIPrintSettings::kPaperSizeInches, // DMPAPER_EXECUTIVE
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A3
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A4
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A4SMALL
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A5
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B4
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B5
nsIPrintSettings::kPaperSizeInches, // DMPAPER_FOLIO
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_QUARTO
nsIPrintSettings::kPaperSizeInches, // DMPAPER_10X14
nsIPrintSettings::kPaperSizeInches, // DMPAPER_11X17
nsIPrintSettings::kPaperSizeInches, // DMPAPER_NOTE
nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_9
nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_10
nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_11
nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_12
nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_14
nsIPrintSettings::kPaperSizeInches, // DMPAPER_CSHEET
nsIPrintSettings::kPaperSizeInches, // DMPAPER_DSHEET
nsIPrintSettings::kPaperSizeInches, // DMPAPER_ESHEET
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_DL
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_C5
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_C3
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_C4
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_C6
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_C65
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_B4
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_B5
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_B6
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_ITALY
nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_MONARCH
nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_PERSONAL
nsIPrintSettings::kPaperSizeInches, // DMPAPER_FANFOLD_US
nsIPrintSettings::kPaperSizeInches, // DMPAPER_FANFOLD_STD_GERMAN
nsIPrintSettings::kPaperSizeInches, // DMPAPER_FANFOLD_LGL_GERMAN
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ISO_B4
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JAPANESE_POSTCARD
nsIPrintSettings::kPaperSizeInches, // DMPAPER_9X11
nsIPrintSettings::kPaperSizeInches, // DMPAPER_10X11
nsIPrintSettings::kPaperSizeInches, // DMPAPER_15X11
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_INVITE
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_RESERVED_48
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_RESERVED_49
nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTER_EXTRA
nsIPrintSettings::kPaperSizeInches, // DMPAPER_LEGAL_EXTRA
nsIPrintSettings::kPaperSizeInches, // DMPAPER_TABLOID_EXTRA
nsIPrintSettings::kPaperSizeInches, // DMPAPER_A4_EXTRA
nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTER_TRANSVERSE
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A4_TRANSVERSE
nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTER_EXTRA_TRANSVERSE
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A_PLUS
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B_PLUS
nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTER_PLUS
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A4_PLUS
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A5_TRANSVERSE
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B5_TRANSVERSE
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A3_EXTRA
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A5_EXTRA
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B5_EXTRA
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A2
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A3_TRANSVERSE
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A3_EXTRA_TRANSVERSE
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_DBL_JAPANESE_POSTCARD
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A6
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_KAKU2
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_KAKU3
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_CHOU3
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_CHOU4
nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTER_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A3_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A4_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A5_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B4_JIS_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B5_JIS_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JAPANESE_POSTCARD_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_DBL_JAPANESE_POSTCARD_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A6_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_KAKU2_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_KAKU3_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_CHOU3_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_CHOU4_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B6_JIS
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B6_JIS_ROTATED
nsIPrintSettings::kPaperSizeInches, // DMPAPER_12X11
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_YOU4
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_YOU4_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P16K
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P32K
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P32KBIG
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_1
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_2
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_3
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_4
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_5
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_6
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_7
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_8
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_9
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_10
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P16K_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P32K_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P32KBIG_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_1_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_2_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_3_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_4_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_5_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_6_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_7_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_8_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_9_ROTATED
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_10_ROTATED
};
NS_IMPL_ISUPPORTS_INHERITED(nsPrintSettingsWin,
nsPrintSettings,
nsIPrintSettingsWin)
/** ---------------------------------------------------
* See documentation in nsPrintSettingsWin.h
* @update
*/
nsPrintSettingsWin::nsPrintSettingsWin() :
nsPrintSettings(),
mDeviceName(nullptr),
mDriverName(nullptr),
mDevMode(nullptr)
{
}
/** ---------------------------------------------------
* See documentation in nsPrintSettingsWin.h
* @update
*/
nsPrintSettingsWin::nsPrintSettingsWin(const nsPrintSettingsWin& aPS) :
mDeviceName(nullptr),
mDriverName(nullptr),
mDevMode(nullptr)
{
*this = aPS;
}
/** ---------------------------------------------------
* See documentation in nsPrintSettingsWin.h
* @update
*/
nsPrintSettingsWin::~nsPrintSettingsWin()
{
if (mDeviceName) free(mDeviceName);
if (mDriverName) free(mDriverName);
if (mDevMode) ::HeapFree(::GetProcessHeap(), 0, mDevMode);
}
NS_IMETHODIMP nsPrintSettingsWin::SetDeviceName(const char16_t * aDeviceName)
{
if (mDeviceName) {
free(mDeviceName);
}
mDeviceName = aDeviceName?wcsdup(char16ptr_t(aDeviceName)):nullptr;
return NS_OK;
}
NS_IMETHODIMP nsPrintSettingsWin::GetDeviceName(char16_t **aDeviceName)
{
NS_ENSURE_ARG_POINTER(aDeviceName);
*aDeviceName = mDeviceName?reinterpret_cast<char16_t*>(wcsdup(mDeviceName)):nullptr;
return NS_OK;
}
NS_IMETHODIMP nsPrintSettingsWin::SetDriverName(const char16_t * aDriverName)
{
if (mDriverName) {
free(mDriverName);
}
mDriverName = aDriverName?wcsdup(char16ptr_t(aDriverName)):nullptr;
return NS_OK;
}
NS_IMETHODIMP nsPrintSettingsWin::GetDriverName(char16_t **aDriverName)
{
NS_ENSURE_ARG_POINTER(aDriverName);
*aDriverName = mDriverName?reinterpret_cast<char16_t*>(wcsdup(mDriverName)):nullptr;
return NS_OK;
}
void nsPrintSettingsWin::CopyDevMode(DEVMODEW* aInDevMode, DEVMODEW *& aOutDevMode)
{
aOutDevMode = nullptr;
size_t size = aInDevMode->dmSize + aInDevMode->dmDriverExtra;
aOutDevMode = (LPDEVMODEW)::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, size);
if (aOutDevMode) {
memcpy(aOutDevMode, aInDevMode, size);
}
}
NS_IMETHODIMP nsPrintSettingsWin::GetDevMode(DEVMODEW * *aDevMode)
{
NS_ENSURE_ARG_POINTER(aDevMode);
if (mDevMode) {
CopyDevMode(mDevMode, *aDevMode);
} else {
*aDevMode = nullptr;
}
return NS_OK;
}
NS_IMETHODIMP nsPrintSettingsWin::SetDevMode(DEVMODEW * aDevMode)
{
if (mDevMode) {
::HeapFree(::GetProcessHeap(), 0, mDevMode);
mDevMode = nullptr;
}
if (aDevMode) {
CopyDevMode(aDevMode, mDevMode);
}
return NS_OK;
}
NS_IMETHODIMP
nsPrintSettingsWin::GetPrintableWidthInInches(double* aPrintableWidthInInches)
{
MOZ_ASSERT(aPrintableWidthInInches);
*aPrintableWidthInInches = mPrintableWidthInInches;
return NS_OK;
}
NS_IMETHODIMP
nsPrintSettingsWin::SetPrintableWidthInInches(double aPrintableWidthInInches)
{
mPrintableWidthInInches = aPrintableWidthInInches;
return NS_OK;
}
NS_IMETHODIMP
nsPrintSettingsWin::GetPrintableHeightInInches(double* aPrintableHeightInInches)
{
MOZ_ASSERT(aPrintableHeightInInches);
*aPrintableHeightInInches = mPrintableHeightInInches;
return NS_OK;
}
NS_IMETHODIMP
nsPrintSettingsWin::SetPrintableHeightInInches(double aPrintableHeightInInches)
{
mPrintableHeightInInches = aPrintableHeightInInches;
return NS_OK;
}
NS_IMETHODIMP
nsPrintSettingsWin::GetEffectivePageSize(double *aWidth, double *aHeight)
{
// If printable page size not set, fall back to nsPrintSettings.
if (mPrintableWidthInInches == 0l || mPrintableHeightInInches == 0l) {
return nsPrintSettings::GetEffectivePageSize(aWidth, aHeight);
}
if (mOrientation == kPortraitOrientation) {
*aWidth = NS_INCHES_TO_TWIPS(mPrintableWidthInInches);
*aHeight = NS_INCHES_TO_TWIPS(mPrintableHeightInInches);
} else {
*aHeight = NS_INCHES_TO_TWIPS(mPrintableWidthInInches);
*aWidth = NS_INCHES_TO_TWIPS(mPrintableHeightInInches);
}
return NS_OK;
}
void
nsPrintSettingsWin::CopyFromNative(HDC aHdc, DEVMODEW* aDevMode)
{
MOZ_ASSERT(aHdc);
MOZ_ASSERT(aDevMode);
mIsInitedFromPrinter = true;
if (aDevMode->dmFields & DM_ORIENTATION) {
mOrientation = int32_t(aDevMode->dmOrientation == DMORIENT_PORTRAIT
? kPortraitOrientation : kLandscapeOrientation);
}
if (aDevMode->dmFields & DM_COPIES) {
mNumCopies = aDevMode->dmCopies;
}
// Since we do the scaling, grab their value and reset back to 100.
if (aDevMode->dmFields & DM_SCALE) {
double scale = double(aDevMode->dmScale) / 100.0f;
if (mScaling == 1.0 || scale != 1.0) {
mScaling = scale;
}
aDevMode->dmScale = 100;
}
if (aDevMode->dmFields & DM_PAPERSIZE) {
mPaperData = aDevMode->dmPaperSize;
// If not a paper size we know about, the unit will be the last one saved.
if (mPaperData > 0 &&
mPaperData < int32_t(mozilla::ArrayLength(kPaperSizeUnits))) {
mPaperSizeUnit = kPaperSizeUnits[mPaperData];
}
} else {
mPaperData = -1;
}
// The length and width in DEVMODE are always in tenths of a millimeter.
double sizeUnitToTenthsOfAmm =
10L * (mPaperSizeUnit == kPaperSizeInches ? MM_PER_INCH_FLOAT : 1L);
if (aDevMode->dmFields & DM_PAPERLENGTH) {
mPaperHeight = aDevMode->dmPaperLength / sizeUnitToTenthsOfAmm;
} else {
mPaperHeight = -1l;
}
if (aDevMode->dmFields & DM_PAPERWIDTH) {
mPaperWidth = aDevMode->dmPaperWidth / sizeUnitToTenthsOfAmm;
} else {
mPaperWidth = -1l;
}
// On Windows we currently create a surface using the printable area of the
// page and don't set the unwriteable [sic] margins. Using the unwriteable
// margins doesn't appear to work on Windows, but I am not sure if this is a
// bug elsewhere in our code or a Windows quirk.
// Note: we only scale the printing using the LOGPIXELSY, so we use that
// when calculating the surface width as well as the height.
int32_t printableWidthInDots = GetDeviceCaps(aHdc, HORZRES);
int32_t printableHeightInDots = GetDeviceCaps(aHdc, VERTRES);
int32_t heightDPI = GetDeviceCaps(aHdc, LOGPIXELSY);
// Keep these values in portrait format, so we can reflect our own changes
// to mOrientation.
if (mOrientation == kPortraitOrientation) {
mPrintableWidthInInches = double(printableWidthInDots) / heightDPI;
mPrintableHeightInInches = double(printableHeightInDots) / heightDPI;
} else {
mPrintableHeightInInches = double(printableWidthInDots) / heightDPI;
mPrintableWidthInInches = double(printableHeightInDots) / heightDPI;
}
// Using Y to match existing code for print scaling calculations.
mResolution = heightDPI;
}
void
nsPrintSettingsWin::CopyToNative(DEVMODEW* aDevMode)
{
MOZ_ASSERT(aDevMode);
if (mPaperData >= 0) {
aDevMode->dmPaperSize = mPaperData;
aDevMode->dmFields |= DM_PAPERSIZE;
} else {
aDevMode->dmPaperSize = 0;
aDevMode->dmFields &= ~DM_PAPERSIZE;
}
// The length and width in DEVMODE are always in tenths of a millimeter.
double sizeUnitToTenthsOfAmm =
10L * (mPaperSizeUnit == kPaperSizeInches ? MM_PER_INCH_FLOAT : 1L);
// Note: small page sizes can be required here for sticker, label and slide
// printers etc. see bug 1271900.
if (mPaperHeight > 0) {
aDevMode->dmPaperLength = mPaperHeight * sizeUnitToTenthsOfAmm;
aDevMode->dmFields |= DM_PAPERLENGTH;
} else {
aDevMode->dmPaperLength = 0;
aDevMode->dmFields &= ~DM_PAPERLENGTH;
}
if (mPaperWidth > 0) {
aDevMode->dmPaperWidth = mPaperWidth * sizeUnitToTenthsOfAmm;
aDevMode->dmFields |= DM_PAPERWIDTH;
} else {
aDevMode->dmPaperWidth = 0;
aDevMode->dmFields &= ~DM_PAPERWIDTH;
}
// Setup Orientation
aDevMode->dmOrientation = mOrientation == kPortraitOrientation
? DMORIENT_PORTRAIT : DMORIENT_LANDSCAPE;
aDevMode->dmFields |= DM_ORIENTATION;
// Setup Number of Copies
aDevMode->dmCopies = mNumCopies;
aDevMode->dmFields |= DM_COPIES;
}
//-------------------------------------------
nsresult
nsPrintSettingsWin::_Clone(nsIPrintSettings **_retval)
{
RefPtr<nsPrintSettingsWin> printSettings = new nsPrintSettingsWin(*this);
printSettings.forget(_retval);
return NS_OK;
}
//-------------------------------------------
nsPrintSettingsWin& nsPrintSettingsWin::operator=(const nsPrintSettingsWin& rhs)
{
if (this == &rhs) {
return *this;
}
((nsPrintSettings&) *this) = rhs;
if (mDeviceName) {
free(mDeviceName);
}
if (mDriverName) {
free(mDriverName);
}
// Use free because we used the native malloc to create the memory
if (mDevMode) {
::HeapFree(::GetProcessHeap(), 0, mDevMode);
}
mDeviceName = rhs.mDeviceName?wcsdup(rhs.mDeviceName):nullptr;
mDriverName = rhs.mDriverName?wcsdup(rhs.mDriverName):nullptr;
if (rhs.mDevMode) {
CopyDevMode(rhs.mDevMode, mDevMode);
} else {
mDevMode = nullptr;
}
return *this;
}
//-------------------------------------------
nsresult
nsPrintSettingsWin::_Assign(nsIPrintSettings *aPS)
{
nsPrintSettingsWin *psWin = static_cast<nsPrintSettingsWin*>(aPS);
*this = *psWin;
return NS_OK;
}
//----------------------------------------------------------------------
// Testing of assign and clone
// This define turns on the testing module below
// so at start up it writes and reads the prefs.
#ifdef DEBUG_rodsX
#include "nsIPrintOptions.h"
#include "nsIServiceManager.h"
class Tester {
public:
Tester();
};
Tester::Tester()
{
nsCOMPtr<nsIPrintSettings> ps;
nsresult rv;
nsCOMPtr<nsIPrintOptions> printService = do_GetService("@mozilla.org/gfx/printsettings-service;1", &rv);
if (NS_SUCCEEDED(rv)) {
rv = printService->CreatePrintSettings(getter_AddRefs(ps));
}
if (ps) {
ps->SetPrintOptions(nsIPrintSettings::kPrintOddPages, true);
ps->SetPrintOptions(nsIPrintSettings::kPrintEvenPages, false);
ps->SetMarginTop(1.0);
ps->SetMarginLeft(1.0);
ps->SetMarginBottom(1.0);
ps->SetMarginRight(1.0);
ps->SetScaling(0.5);
ps->SetPrintBGColors(true);
ps->SetPrintBGImages(true);
ps->SetPrintRange(15);
ps->SetHeaderStrLeft(NS_ConvertUTF8toUTF16("Left").get());
ps->SetHeaderStrCenter(NS_ConvertUTF8toUTF16("Center").get());
ps->SetHeaderStrRight(NS_ConvertUTF8toUTF16("Right").get());
ps->SetFooterStrLeft(NS_ConvertUTF8toUTF16("Left").get());
ps->SetFooterStrCenter(NS_ConvertUTF8toUTF16("Center").get());
ps->SetFooterStrRight(NS_ConvertUTF8toUTF16("Right").get());
ps->SetPaperName(NS_ConvertUTF8toUTF16("Paper Name").get());
ps->SetPaperData(1);
ps->SetPaperWidth(100.0);
ps->SetPaperHeight(50.0);
ps->SetPaperSizeUnit(nsIPrintSettings::kPaperSizeMillimeters);
ps->SetPrintReversed(true);
ps->SetPrintInColor(true);
ps->SetOrientation(nsIPrintSettings::kLandscapeOrientation);
ps->SetPrintCommand(NS_ConvertUTF8toUTF16("Command").get());
ps->SetNumCopies(2);
ps->SetPrinterName(NS_ConvertUTF8toUTF16("Printer Name").get());
ps->SetPrintToFile(true);
ps->SetToFileName(NS_ConvertUTF8toUTF16("File Name").get());
ps->SetPrintPageDelay(1000);
nsCOMPtr<nsIPrintSettings> ps2;
if (NS_SUCCEEDED(rv)) {
rv = printService->CreatePrintSettings(getter_AddRefs(ps2));
}
ps2->Assign(ps);
nsCOMPtr<nsIPrintSettings> psClone;
ps2->Clone(getter_AddRefs(psClone));
}
}
Tester gTester;
#endif

View file

@ -0,0 +1,59 @@
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsPrintSettingsWin_h__
#define nsPrintSettingsWin_h__
#include "nsPrintSettingsImpl.h"
#include "nsIPrintSettingsWin.h"
#include <windows.h>
//*****************************************************************************
//*** nsPrintSettingsWin
//*****************************************************************************
class nsPrintSettingsWin : public nsPrintSettings,
public nsIPrintSettingsWin
{
virtual ~nsPrintSettingsWin();
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIPRINTSETTINGSWIN
nsPrintSettingsWin();
nsPrintSettingsWin(const nsPrintSettingsWin& aPS);
/**
* Makes a new copy
*/
virtual nsresult _Clone(nsIPrintSettings **_retval);
/**
* Assigns values
*/
virtual nsresult _Assign(nsIPrintSettings* aPS);
/**
* Assignment
*/
nsPrintSettingsWin& operator=(const nsPrintSettingsWin& rhs);
NS_IMETHOD GetEffectivePageSize(double *aWidth, double *aHeight) override;
protected:
void CopyDevMode(DEVMODEW* aInDevMode, DEVMODEW *& aOutDevMode);
wchar_t* mDeviceName;
wchar_t* mDriverName;
LPDEVMODEW mDevMode;
double mPrintableWidthInInches = 0l;
double mPrintableHeightInInches = 0l;
};
#endif /* nsPrintSettingsWin_h__ */

View file

@ -0,0 +1,181 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsScreenManagerWin.h"
#include "mozilla/gfx/2D.h"
#include "nsScreenWin.h"
#include "gfxWindowsPlatform.h"
#include "nsIWidget.h"
#include "WinUtils.h"
using namespace mozilla;
BOOL CALLBACK CountMonitors(HMONITOR, HDC, LPRECT, LPARAM ioCount);
nsScreenManagerWin::nsScreenManagerWin()
: mNumberOfScreens(0)
{
// nothing to do. I guess we could cache a bunch of information
// here, but we want to ask the device at runtime in case anything
// has changed.
}
nsScreenManagerWin::~nsScreenManagerWin()
{
}
// addref, release, QI
NS_IMPL_ISUPPORTS(nsScreenManagerWin, nsIScreenManager)
//
// CreateNewScreenObject
//
// Utility routine. Creates a new screen object from the given device handle
//
// NOTE: For this "single-monitor" impl, we just always return the cached primary
// screen. This should change when a multi-monitor impl is done.
//
nsIScreen*
nsScreenManagerWin::CreateNewScreenObject(HMONITOR inScreen)
{
nsIScreen* retScreen = nullptr;
// look through our screen list, hoping to find it. If it's not there,
// add it and return the new one.
for (unsigned i = 0; i < mScreenList.Length(); ++i) {
ScreenListItem& curr = mScreenList[i];
if (inScreen == curr.mMon) {
NS_IF_ADDREF(retScreen = curr.mScreen.get());
return retScreen;
}
} // for each screen.
retScreen = new nsScreenWin(inScreen);
mScreenList.AppendElement(ScreenListItem(inScreen, retScreen));
NS_IF_ADDREF(retScreen);
return retScreen;
}
NS_IMETHODIMP
nsScreenManagerWin::ScreenForId(uint32_t aId, nsIScreen **outScreen)
{
*outScreen = nullptr;
for (unsigned i = 0; i < mScreenList.Length(); ++i) {
ScreenListItem& curr = mScreenList[i];
uint32_t id;
nsresult rv = curr.mScreen->GetId(&id);
if (NS_SUCCEEDED(rv) && id == aId) {
NS_IF_ADDREF(*outScreen = curr.mScreen.get());
return NS_OK;
}
}
return NS_ERROR_FAILURE;
}
//
// ScreenForRect
//
// Returns the screen that contains the rectangle. If the rect overlaps
// multiple screens, it picks the screen with the greatest area of intersection.
//
// The coordinates are in pixels (not twips) and in logical screen coordinates.
//
NS_IMETHODIMP
nsScreenManagerWin::ScreenForRect(int32_t inLeft, int32_t inTop,
int32_t inWidth, int32_t inHeight,
nsIScreen **outScreen)
{
if (!(inWidth || inHeight)) {
NS_WARNING("trying to find screen for sizeless window, using primary monitor");
*outScreen = CreateNewScreenObject(nullptr); // addrefs
return NS_OK;
}
gfx::Rect logicalBounds(inLeft, inTop, inWidth, inHeight);
HMONITOR genScreen = widget::WinUtils::MonitorFromRect(logicalBounds);
*outScreen = CreateNewScreenObject(genScreen); // addrefs
return NS_OK;
} // ScreenForRect
//
// GetPrimaryScreen
//
// The screen with the menubar/taskbar. This shouldn't be needed very
// often.
//
NS_IMETHODIMP
nsScreenManagerWin::GetPrimaryScreen(nsIScreen** aPrimaryScreen)
{
*aPrimaryScreen = CreateNewScreenObject(nullptr); // addrefs
return NS_OK;
} // GetPrimaryScreen
//
// CountMonitors
//
// Will be called once for every monitor in the system. Just
// increments the parameter, which holds a ptr to a PRUin32 holding the
// count up to this point.
//
BOOL CALLBACK
CountMonitors(HMONITOR, HDC, LPRECT, LPARAM ioParam)
{
uint32_t* countPtr = reinterpret_cast<uint32_t*>(ioParam);
++(*countPtr);
return TRUE; // continue the enumeration
} // CountMonitors
//
// GetNumberOfScreens
//
// Returns how many physical screens are available.
//
NS_IMETHODIMP
nsScreenManagerWin::GetNumberOfScreens(uint32_t *aNumberOfScreens)
{
if (mNumberOfScreens)
*aNumberOfScreens = mNumberOfScreens;
else {
uint32_t count = 0;
BOOL result = ::EnumDisplayMonitors(nullptr, nullptr, (MONITORENUMPROC)CountMonitors, (LPARAM)&count);
if (!result)
return NS_ERROR_FAILURE;
*aNumberOfScreens = mNumberOfScreens = count;
}
return NS_OK;
} // GetNumberOfScreens
NS_IMETHODIMP
nsScreenManagerWin::GetSystemDefaultScale(float *aDefaultScale)
{
HMONITOR primary = widget::WinUtils::GetPrimaryMonitor();
*aDefaultScale = float(widget::WinUtils::LogToPhysFactor(primary));
return NS_OK;
}
NS_IMETHODIMP
nsScreenManagerWin::ScreenForNativeWidget(void *aWidget, nsIScreen **outScreen)
{
HMONITOR mon = MonitorFromWindow((HWND) aWidget, MONITOR_DEFAULTTOPRIMARY);
*outScreen = CreateNewScreenObject(mon);
return NS_OK;
}

View file

@ -0,0 +1,50 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsScreenManagerWin_h___
#define nsScreenManagerWin_h___
#include "nsIScreenManager.h"
#include <windows.h>
#include "nsCOMPtr.h"
#include "nsTArray.h"
#include "mozilla/Attributes.h"
class nsIScreen;
//------------------------------------------------------------------------
class ScreenListItem
{
public:
ScreenListItem ( HMONITOR inMon, nsIScreen* inScreen )
: mMon(inMon), mScreen(inScreen) { } ;
HMONITOR mMon;
nsCOMPtr<nsIScreen> mScreen;
};
class nsScreenManagerWin final : public nsIScreenManager
{
public:
nsScreenManagerWin ( );
NS_DECL_ISUPPORTS
NS_DECL_NSISCREENMANAGER
private:
~nsScreenManagerWin();
nsIScreen* CreateNewScreenObject ( HMONITOR inScreen ) ;
uint32_t mNumberOfScreens;
// cache the screens to avoid the memory allocations
AutoTArray<ScreenListItem, 8> mScreenList;
};
#endif // nsScreenManagerWin_h___

View file

@ -0,0 +1,199 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsScreenWin.h"
#include "nsCoord.h"
#include "nsIWidget.h"
#include "WinUtils.h"
using namespace mozilla;
static uint32_t sScreenId;
nsScreenWin::nsScreenWin(HMONITOR inScreen)
: mScreen(inScreen)
, mId(++sScreenId)
{
#ifdef DEBUG
HDC hDCScreen = ::GetDC(nullptr);
NS_ASSERTION(hDCScreen,"GetDC Failure");
NS_ASSERTION(::GetDeviceCaps(hDCScreen, TECHNOLOGY) == DT_RASDISPLAY, "Not a display screen");
::ReleaseDC(nullptr,hDCScreen);
#endif
// nothing else to do. I guess we could cache a bunch of information
// here, but we want to ask the device at runtime in case anything
// has changed.
}
nsScreenWin::~nsScreenWin()
{
// nothing to see here.
}
NS_IMETHODIMP
nsScreenWin::GetId(uint32_t *outId)
{
*outId = mId;
return NS_OK;
}
NS_IMETHODIMP
nsScreenWin::GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight)
{
BOOL success = FALSE;
if (mScreen) {
MONITORINFO info;
info.cbSize = sizeof(MONITORINFO);
success = ::GetMonitorInfoW(mScreen, &info);
if (success) {
*outLeft = info.rcMonitor.left;
*outTop = info.rcMonitor.top;
*outWidth = info.rcMonitor.right - info.rcMonitor.left;
*outHeight = info.rcMonitor.bottom - info.rcMonitor.top;
}
}
if (!success) {
HDC hDCScreen = ::GetDC(nullptr);
NS_ASSERTION(hDCScreen,"GetDC Failure");
*outTop = *outLeft = 0;
*outWidth = ::GetDeviceCaps(hDCScreen, HORZRES);
*outHeight = ::GetDeviceCaps(hDCScreen, VERTRES);
::ReleaseDC(nullptr, hDCScreen);
}
return NS_OK;
} // GetRect
NS_IMETHODIMP
nsScreenWin::GetAvailRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight)
{
BOOL success = FALSE;
if (mScreen) {
MONITORINFO info;
info.cbSize = sizeof(MONITORINFO);
success = ::GetMonitorInfoW(mScreen, &info);
if (success) {
*outLeft = info.rcWork.left;
*outTop = info.rcWork.top;
*outWidth = info.rcWork.right - info.rcWork.left;
*outHeight = info.rcWork.bottom - info.rcWork.top;
}
}
if (!success) {
RECT workArea;
::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
*outLeft = workArea.left;
*outTop = workArea.top;
*outWidth = workArea.right - workArea.left;
*outHeight = workArea.bottom - workArea.top;
}
return NS_OK;
} // GetAvailRect
NS_IMETHODIMP
nsScreenWin::GetRectDisplayPix(int32_t *outLeft, int32_t *outTop,
int32_t *outWidth, int32_t *outHeight)
{
if (widget::WinUtils::IsPerMonitorDPIAware()) {
// on per-monitor-dpi config, display pixels are device pixels
return GetRect(outLeft, outTop, outWidth, outHeight);
}
int32_t left, top, width, height;
nsresult rv = GetRect(&left, &top, &width, &height);
if (NS_FAILED(rv)) {
return rv;
}
double scaleFactor = 1.0 / widget::WinUtils::LogToPhysFactor(mScreen);
*outLeft = NSToIntRound(left * scaleFactor);
*outTop = NSToIntRound(top * scaleFactor);
*outWidth = NSToIntRound(width * scaleFactor);
*outHeight = NSToIntRound(height * scaleFactor);
return NS_OK;
}
NS_IMETHODIMP
nsScreenWin::GetAvailRectDisplayPix(int32_t *outLeft, int32_t *outTop,
int32_t *outWidth, int32_t *outHeight)
{
if (widget::WinUtils::IsPerMonitorDPIAware()) {
// on per-monitor-dpi config, display pixels are device pixels
return GetAvailRect(outLeft, outTop, outWidth, outHeight);
}
int32_t left, top, width, height;
nsresult rv = GetAvailRect(&left, &top, &width, &height);
if (NS_FAILED(rv)) {
return rv;
}
double scaleFactor = 1.0 / widget::WinUtils::LogToPhysFactor(mScreen);
*outLeft = NSToIntRound(left * scaleFactor);
*outTop = NSToIntRound(top * scaleFactor);
*outWidth = NSToIntRound(width * scaleFactor);
*outHeight = NSToIntRound(height * scaleFactor);
return NS_OK;
}
NS_IMETHODIMP
nsScreenWin :: GetPixelDepth(int32_t *aPixelDepth)
{
//XXX not sure how to get this info for multiple monitors, this might be ok...
HDC hDCScreen = ::GetDC(nullptr);
NS_ASSERTION(hDCScreen,"GetDC Failure");
int32_t depth = ::GetDeviceCaps(hDCScreen, BITSPIXEL);
if (depth == 32) {
// If a device uses 32 bits per pixel, it's still only using 8 bits
// per color component, which is what our callers want to know.
// (Some devices report 32 and some devices report 24.)
depth = 24;
}
*aPixelDepth = depth;
::ReleaseDC(nullptr, hDCScreen);
return NS_OK;
} // GetPixelDepth
NS_IMETHODIMP
nsScreenWin::GetColorDepth(int32_t *aColorDepth)
{
return GetPixelDepth(aColorDepth);
} // GetColorDepth
NS_IMETHODIMP
nsScreenWin::GetContentsScaleFactor(double *aContentsScaleFactor)
{
if (widget::WinUtils::IsPerMonitorDPIAware()) {
*aContentsScaleFactor = 1.0;
} else {
*aContentsScaleFactor = widget::WinUtils::LogToPhysFactor(mScreen);
}
return NS_OK;
}
NS_IMETHODIMP
nsScreenWin::GetDefaultCSSScaleFactor(double* aScaleFactor)
{
double scale = nsIWidget::DefaultScaleOverride();
if (scale > 0.0) {
*aScaleFactor = scale;
} else {
*aScaleFactor = widget::WinUtils::LogToPhysFactor(mScreen);
}
return NS_OK;
}

View file

@ -0,0 +1,45 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsScreenWin_h___
#define nsScreenWin_h___
#include <windows.h>
#include "nsBaseScreen.h"
//------------------------------------------------------------------------
class nsScreenWin final : public nsBaseScreen
{
public:
nsScreenWin ( HMONITOR inScreen );
~nsScreenWin();
NS_IMETHOD GetId(uint32_t* aId);
// These methods return the size in device (physical) pixels
NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight);
NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight);
// And these methods get the screen size in 'desktop pixels' (AKA 'logical pixels')
// that are dependent on the logical DPI setting in windows
NS_IMETHOD GetRectDisplayPix(int32_t *outLeft, int32_t *outTop,
int32_t *outWidth, int32_t *outHeight);
NS_IMETHOD GetAvailRectDisplayPix(int32_t *outLeft, int32_t *outTop,
int32_t *outWidth, int32_t *outHeight);
NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth);
NS_IMETHOD GetColorDepth(int32_t* aColorDepth);
NS_IMETHOD GetContentsScaleFactor(double* aContentsScaleFactor) override;
NS_IMETHOD GetDefaultCSSScaleFactor(double* aScaleFactor) override;
private:
HMONITOR mScreen;
uint32_t mId;
};
#endif // nsScreenWin_h___

305
widget/windows/nsSound.cpp Normal file
View file

@ -0,0 +1,305 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nscore.h"
#include "plstr.h"
#include <stdio.h>
#include "nsString.h"
#include <windows.h>
// mmsystem.h is needed to build with WIN32_LEAN_AND_MEAN
#include <mmsystem.h>
#include "nsSound.h"
#include "nsIURL.h"
#include "nsNetUtil.h"
#include "nsIChannel.h"
#include "nsContentUtils.h"
#include "nsCRT.h"
#include "mozilla/Logging.h"
#include "prtime.h"
#include "prprf.h"
#include "prmem.h"
#include "nsNativeCharsetUtils.h"
#include "nsThreadUtils.h"
using mozilla::LogLevel;
PRLogModuleInfo* gWin32SoundLog = nullptr;
class nsSoundPlayer: public mozilla::Runnable {
public:
nsSoundPlayer(nsSound *aSound, const wchar_t* aSoundName) :
mSoundName(aSoundName), mSound(aSound)
{
Init();
}
nsSoundPlayer(nsSound *aSound, const nsAString& aSoundName) :
mSoundName(aSoundName), mSound(aSound)
{
Init();
}
NS_DECL_NSIRUNNABLE
protected:
nsString mSoundName;
nsSound *mSound; // Strong, but this will be released from SoundReleaser.
nsCOMPtr<nsIThread> mThread;
void Init()
{
NS_GetCurrentThread(getter_AddRefs(mThread));
NS_ASSERTION(mThread, "failed to get current thread");
NS_IF_ADDREF(mSound);
}
class SoundReleaser: public mozilla::Runnable {
public:
SoundReleaser(nsSound* aSound) :
mSound(aSound)
{
}
NS_DECL_NSIRUNNABLE
protected:
nsSound *mSound;
};
};
NS_IMETHODIMP
nsSoundPlayer::Run()
{
PR_SetCurrentThreadName("Play Sound");
NS_PRECONDITION(!mSoundName.IsEmpty(), "Sound name should not be empty");
::PlaySoundW(mSoundName.get(), nullptr,
SND_NODEFAULT | SND_ALIAS | SND_ASYNC);
nsCOMPtr<nsIRunnable> releaser = new SoundReleaser(mSound);
// Don't release nsSound from here, because here is not an owning thread of
// the nsSound. nsSound must be released in its owning thread.
mThread->Dispatch(releaser, NS_DISPATCH_NORMAL);
return NS_OK;
}
NS_IMETHODIMP
nsSoundPlayer::SoundReleaser::Run()
{
mSound->ShutdownOldPlayerThread();
NS_IF_RELEASE(mSound);
return NS_OK;
}
#ifndef SND_PURGE
// Not available on Windows CE, and according to MSDN
// doesn't do anything on recent windows either.
#define SND_PURGE 0
#endif
NS_IMPL_ISUPPORTS(nsSound, nsISound, nsIStreamLoaderObserver)
nsSound::nsSound()
{
if (!gWin32SoundLog) {
gWin32SoundLog = PR_NewLogModule("nsSound");
}
mLastSound = nullptr;
}
nsSound::~nsSound()
{
NS_ASSERTION(!mPlayerThread, "player thread is not null but should be");
PurgeLastSound();
}
void nsSound::ShutdownOldPlayerThread()
{
nsCOMPtr<nsIThread> playerThread(mPlayerThread.forget());
if (playerThread)
playerThread->Shutdown();
}
void nsSound::PurgeLastSound()
{
if (mLastSound) {
// Halt any currently playing sound.
::PlaySound(nullptr, nullptr, SND_PURGE);
// Now delete the buffer.
free(mLastSound);
mLastSound = nullptr;
}
}
NS_IMETHODIMP nsSound::Beep()
{
::MessageBeep(0);
return NS_OK;
}
NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader *aLoader,
nsISupports *context,
nsresult aStatus,
uint32_t dataLen,
const uint8_t *data)
{
// print a load error on bad status
if (NS_FAILED(aStatus)) {
#ifdef DEBUG
if (aLoader) {
nsCOMPtr<nsIRequest> request;
nsCOMPtr<nsIChannel> channel;
aLoader->GetRequest(getter_AddRefs(request));
if (request)
channel = do_QueryInterface(request);
if (channel) {
nsCOMPtr<nsIURI> uri;
channel->GetURI(getter_AddRefs(uri));
if (uri) {
nsAutoCString uriSpec;
uri->GetSpec(uriSpec);
MOZ_LOG(gWin32SoundLog, LogLevel::Info,
("Failed to load %s\n", uriSpec.get()));
}
}
}
#endif
return aStatus;
}
ShutdownOldPlayerThread();
PurgeLastSound();
if (data && dataLen > 0) {
DWORD flags = SND_MEMORY | SND_NODEFAULT;
// We try to make a copy so we can play it async.
mLastSound = (uint8_t *) malloc(dataLen);
if (mLastSound) {
memcpy(mLastSound, data, dataLen);
data = mLastSound;
flags |= SND_ASYNC;
}
::PlaySoundW(reinterpret_cast<LPCWSTR>(data), 0, flags);
}
return NS_OK;
}
NS_IMETHODIMP nsSound::Play(nsIURL *aURL)
{
nsresult rv;
#ifdef DEBUG_SOUND
char *url;
aURL->GetSpec(&url);
MOZ_LOG(gWin32SoundLog, LogLevel::Info,
("%s\n", url));
#endif
nsCOMPtr<nsIStreamLoader> loader;
rv = NS_NewStreamLoader(getter_AddRefs(loader),
aURL,
this, // aObserver
nsContentUtils::GetSystemPrincipal(),
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
nsIContentPolicy::TYPE_OTHER);
return rv;
}
NS_IMETHODIMP nsSound::Init()
{
// This call halts a sound if it was still playing.
// We have to use the sound library for something to make sure
// it is initialized.
// If we wait until the first sound is played, there will
// be a time lag as the library gets loaded.
::PlaySound(nullptr, nullptr, SND_PURGE);
return NS_OK;
}
NS_IMETHODIMP nsSound::PlaySystemSound(const nsAString &aSoundAlias)
{
ShutdownOldPlayerThread();
PurgeLastSound();
if (!NS_IsMozAliasSound(aSoundAlias)) {
if (aSoundAlias.IsEmpty())
return NS_OK;
nsCOMPtr<nsIRunnable> player = new nsSoundPlayer(this, aSoundAlias);
NS_ENSURE_TRUE(player, NS_ERROR_OUT_OF_MEMORY);
nsresult rv = NS_NewThread(getter_AddRefs(mPlayerThread), player);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_WARNING("nsISound::playSystemSound is called with \"_moz_\" events, they are obsolete, use nsISound::playEventSound instead");
uint32_t eventId;
if (aSoundAlias.Equals(NS_SYSSOUND_MAIL_BEEP))
eventId = EVENT_NEW_MAIL_RECEIVED;
else if (aSoundAlias.Equals(NS_SYSSOUND_CONFIRM_DIALOG))
eventId = EVENT_CONFIRM_DIALOG_OPEN;
else if (aSoundAlias.Equals(NS_SYSSOUND_ALERT_DIALOG))
eventId = EVENT_ALERT_DIALOG_OPEN;
else if (aSoundAlias.Equals(NS_SYSSOUND_MENU_EXECUTE))
eventId = EVENT_MENU_EXECUTE;
else if (aSoundAlias.Equals(NS_SYSSOUND_MENU_POPUP))
eventId = EVENT_MENU_POPUP;
else
return NS_OK;
return PlayEventSound(eventId);
}
NS_IMETHODIMP nsSound::PlayEventSound(uint32_t aEventId)
{
ShutdownOldPlayerThread();
PurgeLastSound();
const wchar_t *sound = nullptr;
switch (aEventId) {
case EVENT_NEW_MAIL_RECEIVED:
sound = L"MailBeep";
break;
case EVENT_ALERT_DIALOG_OPEN:
sound = L"SystemExclamation";
break;
case EVENT_CONFIRM_DIALOG_OPEN:
sound = L"SystemQuestion";
break;
case EVENT_MENU_EXECUTE:
sound = L"MenuCommand";
break;
case EVENT_MENU_POPUP:
sound = L"MenuPopup";
break;
case EVENT_EDITOR_MAX_LEN:
sound = L".Default";
break;
default:
// Win32 plays no sounds at NS_SYSSOUND_PROMPT_DIALOG and
// NS_SYSSOUND_SELECT_DIALOG.
return NS_OK;
}
NS_ASSERTION(sound, "sound is null");
nsCOMPtr<nsIRunnable> player = new nsSoundPlayer(this, sound);
NS_ENSURE_TRUE(player, NS_ERROR_OUT_OF_MEMORY);
nsresult rv = NS_NewThread(getter_AddRefs(mPlayerThread), player);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}

37
widget/windows/nsSound.h Normal file
View file

@ -0,0 +1,37 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __nsSound_h__
#define __nsSound_h__
#include "nsISound.h"
#include "nsIStreamLoader.h"
#include "nsCOMPtr.h"
class nsIThread;
class nsSound : public nsISound,
public nsIStreamLoaderObserver
{
public:
nsSound();
void ShutdownOldPlayerThread();
NS_DECL_ISUPPORTS
NS_DECL_NSISOUND
NS_DECL_NSISTREAMLOADEROBSERVER
private:
virtual ~nsSound();
void PurgeLastSound();
private:
uint8_t* mLastSound;
nsCOMPtr<nsIThread> mPlayerThread;
};
#endif /* __nsSound_h__ */

View file

@ -0,0 +1,81 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsToolkit.h"
#include "nsAppShell.h"
#include "nsWindow.h"
#include "nsWidgetsCID.h"
#include "prmon.h"
#include "prtime.h"
#include "nsIServiceManager.h"
#include "nsComponentManagerUtils.h"
#include <objbase.h>
#include "WinUtils.h"
#include "nsUXThemeData.h"
// unknwn.h is needed to build with WIN32_LEAN_AND_MEAN
#include <unknwn.h>
using namespace mozilla::widget;
nsToolkit* nsToolkit::gToolkit = nullptr;
HINSTANCE nsToolkit::mDllInstance = 0;
//-------------------------------------------------------------------------
//
// constructor
//
//-------------------------------------------------------------------------
nsToolkit::nsToolkit()
{
MOZ_COUNT_CTOR(nsToolkit);
#if defined(MOZ_STATIC_COMPONENT_LIBS)
nsToolkit::Startup(GetModuleHandle(nullptr));
#endif
}
//-------------------------------------------------------------------------
//
// destructor
//
//-------------------------------------------------------------------------
nsToolkit::~nsToolkit()
{
MOZ_COUNT_DTOR(nsToolkit);
}
void
nsToolkit::Startup(HMODULE hModule)
{
nsToolkit::mDllInstance = hModule;
WinUtils::Initialize();
nsUXThemeData::Initialize();
}
void
nsToolkit::Shutdown()
{
delete gToolkit;
gToolkit = nullptr;
}
//-------------------------------------------------------------------------
//
// Return the nsToolkit for the current thread. If a toolkit does not
// yet exist, then one will be created...
//
//-------------------------------------------------------------------------
// static
nsToolkit* nsToolkit::GetToolkit()
{
if (!gToolkit) {
gToolkit = new nsToolkit();
}
return gToolkit;
}

View file

@ -0,0 +1,49 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsToolkit_h__
#define nsToolkit_h__
#include "nsdefs.h"
#include "nsITimer.h"
#include "nsCOMPtr.h"
#include <windows.h>
// Avoid including windowsx.h to prevent macro pollution
#ifndef GET_X_LPARAM
#define GET_X_LPARAM(pt) (short(LOWORD(pt)))
#endif
#ifndef GET_Y_LPARAM
#define GET_Y_LPARAM(pt) (short(HIWORD(pt)))
#endif
/**
* Wrapper around the thread running the message pump.
* The toolkit abstraction is necessary because the message pump must
* execute within the same thread that created the widget under Win32.
*/
class nsToolkit
{
public:
nsToolkit();
private:
~nsToolkit();
public:
static nsToolkit* GetToolkit();
static HINSTANCE mDllInstance;
static void Startup(HMODULE hModule);
static void Shutdown();
protected:
static nsToolkit* gToolkit;
};
#endif // TOOLKIT_H

View file

@ -0,0 +1,251 @@
/* vim: se cin sw=2 ts=2 et : */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsUXThemeConstants_h
#define nsUXThemeConstants_h
/*
* The following constants are used to determine how a widget is drawn using
* Windows' Theme API. For more information on theme parts and states see
* http://msdn.microsoft.com/en-us/library/bb773210(VS.85).aspx
*/
#include <vssym32.h>
#include <vsstyle.h>
#define THEME_COLOR 204
#define THEME_FONT 210
// Generic state constants
#define TS_NORMAL 1
#define TS_HOVER 2
#define TS_ACTIVE 3
#define TS_DISABLED 4
#define TS_FOCUSED 5
// These constants are reversed for the trackbar (scale) thumb
#define TKP_FOCUSED 4
#define TKP_DISABLED 5
// Toolbarbutton constants
#define TB_CHECKED 5
#define TB_HOVER_CHECKED 6
// Button constants
#define BP_BUTTON 1
#define BP_RADIO 2
#define BP_CHECKBOX 3
#define BP_GROUPBOX 4
// Textfield constants
/* This is the EP_EDITTEXT part */
#define TFP_TEXTFIELD 1
#define TFP_EDITBORDER_NOSCROLL 6
#define TFS_READONLY 6
/* These are the state constants for the EDITBORDER parts */
#define TFS_EDITBORDER_NORMAL 1
#define TFS_EDITBORDER_HOVER 2
#define TFS_EDITBORDER_FOCUSED 3
#define TFS_EDITBORDER_DISABLED 4
// Treeview/listbox constants
#define TREEVIEW_BODY 1
// Scrollbar constants
#define SP_BUTTON 1
#define SP_THUMBHOR 2
#define SP_THUMBVERT 3
#define SP_TRACKSTARTHOR 4
#define SP_TRACKENDHOR 5
#define SP_TRACKSTARTVERT 6
#define SP_TRACKENDVERT 7
#define SP_GRIPPERHOR 8
#define SP_GRIPPERVERT 9
// Vista only; implict hover state.
// BASE + 0 = UP, + 1 = DOWN, etc.
#define SP_BUTTON_IMPLICIT_HOVER_BASE 17
// Scale constants
#define TKP_TRACK 1
#define TKP_TRACKVERT 2
#define TKP_THUMB 3
#define TKP_THUMBBOTTOM 4
#define TKP_THUMBTOP 5
#define TKP_THUMBVERT 6
#define TKP_THUMBLEFT 7
#define TKP_THUMBRIGHT 8
// Track state contstants
#define TRS_NORMAL 1
// Track vertical state constants
#define TRVS_NORMAL 1
// Spin constants
#define SPNP_UP 1
#define SPNP_DOWN 2
// Tab constants
#define TABP_TAB 4
#define TABP_TAB_SELECTED 5
#define TABP_PANELS 9
#define TABP_PANEL 10
// Tooltip constants
#define TTP_STANDARD 1
// Dropdown constants
#define CBP_DROPMARKER 1
#define CBP_DROPBORDER 4
/* This is actually the 'READONLY' style */
#define CBP_DROPFRAME 5
#define CBP_DROPMARKER_VISTA 6
// Menu Constants
#define MENU_BARBACKGROUND 7
#define MENU_BARITEM 8
#define MENU_POPUPBACKGROUND 9
#define MENU_POPUPBORDERS 10
#define MENU_POPUPCHECK 11
#define MENU_POPUPCHECKBACKGROUND 12
#define MENU_POPUPGUTTER 13
#define MENU_POPUPITEM 14
#define MENU_POPUPSEPARATOR 15
#define MENU_POPUPSUBMENU 16
#define MENU_SYSTEMCLOSE 17
#define MENU_SYSTEMMAXIMIZE 18
#define MENU_SYSTEMMINIMIZE 19
#define MENU_SYSTEMRESTORE 20
#define MB_ACTIVE 1
#define MB_INACTIVE 2
#define MS_NORMAL 1
#define MS_SELECTED 2
#define MS_DEMOTED 3
#define MBI_NORMAL 1
#define MBI_HOT 2
#define MBI_PUSHED 3
#define MBI_DISABLED 4
#define MBI_DISABLEDHOT 5
#define MBI_DISABLEDPUSHED 6
#define MC_CHECKMARKNORMAL 1
#define MC_CHECKMARKDISABLED 2
#define MC_BULLETNORMAL 3
#define MC_BULLETDISABLED 4
#define MCB_DISABLED 1
#define MCB_NORMAL 2
#define MCB_BITMAP 3
#define MPI_NORMAL 1
#define MPI_HOT 2
#define MPI_DISABLED 3
#define MPI_DISABLEDHOT 4
#define MSM_NORMAL 1
#define MSM_DISABLED 2
// Rebar constants
#define RP_BAND 3
#define RP_BACKGROUND 6
// Constants only found in new (98+, 2K+, XP+, etc.) Windows.
#ifdef DFCS_HOT
#undef DFCS_HOT
#endif
#define DFCS_HOT 0x00001000
#ifdef COLOR_MENUHILIGHT
#undef COLOR_MENUHILIGHT
#endif
#define COLOR_MENUHILIGHT 29
#ifdef SPI_GETFLATMENU
#undef SPI_GETFLATMENU
#endif
#define SPI_GETFLATMENU 0x1022
#ifndef SPI_GETMENUSHOWDELAY
#define SPI_GETMENUSHOWDELAY 106
#endif //SPI_GETMENUSHOWDELAY
#ifndef WS_EX_LAYOUTRTL
#define WS_EX_LAYOUTRTL 0x00400000L // Right to left mirroring
#endif
// Our extra constants for passing a little bit more info to the renderer.
#define DFCS_RTL 0x00010000
// Toolbar separator dimension which can't be gotten from Windows
#define TB_SEPARATOR_HEIGHT 2
namespace mozilla {
namespace widget {
namespace themeconst {
// Pulled from sdk/include/vsstyle.h
enum {
WP_CAPTION = 1,
WP_SMALLCAPTION = 2,
WP_MINCAPTION = 3,
WP_SMALLMINCAPTION = 4,
WP_MAXCAPTION = 5,
WP_SMALLMAXCAPTION = 6,
WP_FRAMELEFT = 7,
WP_FRAMERIGHT = 8,
WP_FRAMEBOTTOM = 9,
WP_SMALLFRAMELEFT = 10,
WP_SMALLFRAMERIGHT = 11,
WP_SMALLFRAMEBOTTOM = 12,
WP_SYSBUTTON = 13,
WP_MDISYSBUTTON = 14,
WP_MINBUTTON = 15,
WP_MDIMINBUTTON = 16,
WP_MAXBUTTON = 17,
WP_CLOSEBUTTON = 18,
WP_SMALLCLOSEBUTTON = 19,
WP_MDICLOSEBUTTON = 20,
WP_RESTOREBUTTON = 21,
WP_MDIRESTOREBUTTON = 22,
WP_HELPBUTTON = 23,
WP_MDIHELPBUTTON = 24,
WP_HORZSCROLL = 25,
WP_HORZTHUMB = 26,
WP_VERTSCROLL = 27,
WP_VERTTHUMB = 28,
WP_DIALOG = 29,
WP_CAPTIONSIZINGTEMPLATE = 30,
WP_SMALLCAPTIONSIZINGTEMPLATE = 31,
WP_FRAMELEFTSIZINGTEMPLATE = 32,
WP_SMALLFRAMELEFTSIZINGTEMPLATE = 33,
WP_FRAMERIGHTSIZINGTEMPLATE = 34,
WP_SMALLFRAMERIGHTSIZINGTEMPLATE = 35,
WP_FRAMEBOTTOMSIZINGTEMPLATE = 36,
WP_SMALLFRAMEBOTTOMSIZINGTEMPLATE = 37,
WP_FRAME = 38
};
enum FRAMESTATES {
FS_ACTIVE = 1,
FS_INACTIVE = 2
};
enum {
BS_NORMAL = 1,
BS_HOT = 2,
BS_PUSHED = 3,
BS_DISABLED = 4,
BS_INACTIVE = 5 /* undocumented, inactive caption button */
};
}}} // mozilla::widget::themeconst
#endif

Some files were not shown because too many files have changed in this diff Show more