mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-16 12:17:34 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
15
gfx/src/AppUnits.h
Normal file
15
gfx/src/AppUnits.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/* -*- Mode: C++; 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 mozilla_AppUnits_h
|
||||
#define mozilla_AppUnits_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mozilla {
|
||||
inline int32_t AppUnitsPerCSSPixel() { return 60; }
|
||||
inline int32_t AppUnitsPerCSSInch() { return 96 * AppUnitsPerCSSPixel(); }
|
||||
} // namespace mozilla
|
||||
#endif /* _NS_APPUNITS_H_ */
|
||||
50
gfx/src/ArrayView.h
Normal file
50
gfx/src/ArrayView.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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_GFX_ARRAY_VIEW_H_
|
||||
#define MOZILLA_GFX_ARRAY_VIEW_H_
|
||||
|
||||
#include "nsTArray.h"
|
||||
|
||||
/* This is similar to mfbt/Range.h but has implicit conversion
|
||||
* from nsTArray and less bounds checking.
|
||||
* For now, prefer Range over ArrayView */
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
template<typename T>
|
||||
class ArrayView
|
||||
{
|
||||
public:
|
||||
MOZ_IMPLICIT ArrayView(const nsTArray<T>& aData) :
|
||||
mData(aData.Elements()), mLength(aData.Length())
|
||||
{
|
||||
}
|
||||
ArrayView(const T* aData, const size_t aLength) :
|
||||
mData(aData), mLength(aLength)
|
||||
{
|
||||
}
|
||||
const T& operator[](const size_t aIdx) const
|
||||
{
|
||||
return mData[aIdx];
|
||||
}
|
||||
size_t Length() const
|
||||
{
|
||||
return mLength;
|
||||
}
|
||||
const T* Data() const
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
private:
|
||||
const T* mData;
|
||||
const size_t mLength;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* MOZILLA_GFX_ARRAY_VIEW_H_ */
|
||||
620
gfx/src/DriverCrashGuard.cpp
Normal file
620
gfx/src/DriverCrashGuard.cpp
Normal file
|
|
@ -0,0 +1,620 @@
|
|||
/* -*- 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 "DriverCrashGuard.h"
|
||||
#include "gfxEnv.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
#include "nsExceptionHandler.h"
|
||||
#endif
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
static const size_t NUM_CRASH_GUARD_TYPES = size_t(CrashGuardType::NUM_TYPES);
|
||||
static const char* sCrashGuardNames[] = {
|
||||
"d3d11layers",
|
||||
"d3d9video",
|
||||
"glcontext",
|
||||
"d3d11video",
|
||||
};
|
||||
static_assert(MOZ_ARRAY_LENGTH(sCrashGuardNames) == NUM_CRASH_GUARD_TYPES,
|
||||
"CrashGuardType updated without a name string");
|
||||
|
||||
static inline void
|
||||
BuildCrashGuardPrefName(CrashGuardType aType, nsCString& aOutPrefName)
|
||||
{
|
||||
MOZ_ASSERT(aType < CrashGuardType::NUM_TYPES);
|
||||
MOZ_ASSERT(sCrashGuardNames[size_t(aType)]);
|
||||
|
||||
aOutPrefName.Assign("gfx.crash-guard.status.");
|
||||
aOutPrefName.Append(sCrashGuardNames[size_t(aType)]);
|
||||
}
|
||||
|
||||
DriverCrashGuard::DriverCrashGuard(CrashGuardType aType, dom::ContentParent* aContentParent)
|
||||
: mType(aType)
|
||||
, mMode(aContentParent ? Mode::Proxy : Mode::Normal)
|
||||
, mInitialized(false)
|
||||
, mGuardActivated(false)
|
||||
, mCrashDetected(false)
|
||||
{
|
||||
BuildCrashGuardPrefName(aType, mStatusPref);
|
||||
}
|
||||
|
||||
void
|
||||
DriverCrashGuard::InitializeIfNeeded()
|
||||
{
|
||||
if (mInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
mInitialized = true;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
static inline bool
|
||||
AreCrashGuardsEnabled()
|
||||
{
|
||||
// Crash guard isn't supported in the GPU process since the entire
|
||||
// process is basically a crash guard.
|
||||
if (XRE_IsGPUProcess()) {
|
||||
return false;
|
||||
}
|
||||
#ifdef NIGHTLY_BUILD
|
||||
// We only use the crash guard on non-nightly channels, since the nightly
|
||||
// channel is for development and having graphics features perma-disabled
|
||||
// is rather annoying. Unless the user forces is with an environment
|
||||
// variable, which comes in handy for testing.
|
||||
return gfxEnv::ForceCrashGuardNightly();
|
||||
#else
|
||||
// Check to see if all guards have been disabled through the environment.
|
||||
if (gfxEnv::DisableCrashGuard()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
DriverCrashGuard::Initialize()
|
||||
{
|
||||
if (!AreCrashGuardsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Using DriverCrashGuard off the main thread currently does not work. Under
|
||||
// e10s it could conceivably work by dispatching the IPC calls via the main
|
||||
// thread. In the parent process this would be harder. For now, we simply
|
||||
// exit early instead.
|
||||
if (!NS_IsMainThread()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mGfxInfo = services::GetGfxInfo();
|
||||
|
||||
if (XRE_IsContentProcess()) {
|
||||
// Ask the parent whether or not activating the guard is okay. The parent
|
||||
// won't bother if it detected a crash.
|
||||
dom::ContentChild* cc = dom::ContentChild::GetSingleton();
|
||||
cc->SendBeginDriverCrashGuard(uint32_t(mType), &mCrashDetected);
|
||||
if (mCrashDetected) {
|
||||
LogFeatureDisabled();
|
||||
return;
|
||||
}
|
||||
|
||||
ActivateGuard();
|
||||
return;
|
||||
}
|
||||
|
||||
// Always check whether or not the lock file exists. For example, we could
|
||||
// have crashed creating a D3D9 device in the parent process, and on restart
|
||||
// are now requesting one in the child process. We catch everything here.
|
||||
if (RecoverFromCrash()) {
|
||||
mCrashDetected = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// If the environment has changed, we always activate the guard. In the
|
||||
// parent process this performs main-thread disk I/O. Child process guards
|
||||
// only incur an IPC cost, so if we're proxying for a child process, we
|
||||
// play it safe and activate the guard as long as we don't expect it to
|
||||
// crash.
|
||||
if (CheckOrRefreshEnvironment() ||
|
||||
(mMode == Mode::Proxy && GetStatus() != DriverInitStatus::Crashed))
|
||||
{
|
||||
ActivateGuard();
|
||||
return;
|
||||
}
|
||||
|
||||
// If we got here and our status is "crashed", then the environment has not
|
||||
// updated and we do not want to attempt to use the driver again.
|
||||
if (GetStatus() == DriverInitStatus::Crashed) {
|
||||
mCrashDetected = true;
|
||||
LogFeatureDisabled();
|
||||
}
|
||||
}
|
||||
|
||||
DriverCrashGuard::~DriverCrashGuard()
|
||||
{
|
||||
if (!mGuardActivated) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
if (mGuardFile) {
|
||||
mGuardFile->Remove(false);
|
||||
}
|
||||
|
||||
// If during our initialization, no other process encountered a crash, we
|
||||
// proceed to mark the status as okay.
|
||||
if (GetStatus() != DriverInitStatus::Crashed) {
|
||||
SetStatus(DriverInitStatus::Okay);
|
||||
}
|
||||
} else {
|
||||
dom::ContentChild::GetSingleton()->SendEndDriverCrashGuard(uint32_t(mType));
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
// Remove the crash report annotation.
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"),
|
||||
NS_LITERAL_CSTRING(""));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
DriverCrashGuard::Crashed()
|
||||
{
|
||||
InitializeIfNeeded();
|
||||
|
||||
// Note, we read mCrashDetected instead of GetStatus(), since in child
|
||||
// processes we're not guaranteed that the prefs have been synced in
|
||||
// time.
|
||||
return mCrashDetected;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile>
|
||||
DriverCrashGuard::GetGuardFile()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
nsCString filename;
|
||||
filename.Assign(sCrashGuardNames[size_t(mType)]);
|
||||
filename.Append(".guard");
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR, getter_AddRefs(file));
|
||||
if (!file) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!NS_SUCCEEDED(file->AppendNative(filename))) {
|
||||
return nullptr;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
void
|
||||
DriverCrashGuard::ActivateGuard()
|
||||
{
|
||||
mGuardActivated = true;
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
// Anotate crash reports only if we're a real guard. Otherwise, we could
|
||||
// attribute a random parent process crash to a graphics problem in a child
|
||||
// process.
|
||||
if (mMode != Mode::Proxy) {
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"),
|
||||
NS_LITERAL_CSTRING("1"));
|
||||
}
|
||||
#endif
|
||||
|
||||
// If we're in the content process, the rest of the guarding is handled
|
||||
// in the parent.
|
||||
if (XRE_IsContentProcess()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetStatus(DriverInitStatus::Attempting);
|
||||
|
||||
if (mMode != Mode::Proxy) {
|
||||
// In parent process guards, we use two tombstones to detect crashes: a
|
||||
// preferences and a zero-byte file on the filesystem.
|
||||
FlushPreferences();
|
||||
|
||||
// Create a temporary tombstone/lockfile.
|
||||
FILE* fp = nullptr;
|
||||
mGuardFile = GetGuardFile();
|
||||
if (!mGuardFile || !NS_SUCCEEDED(mGuardFile->OpenANSIFileDesc("w", &fp))) {
|
||||
return;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DriverCrashGuard::NotifyCrashed()
|
||||
{
|
||||
CheckOrRefreshEnvironment();
|
||||
SetStatus(DriverInitStatus::Crashed);
|
||||
FlushPreferences();
|
||||
LogCrashRecovery();
|
||||
}
|
||||
|
||||
bool
|
||||
DriverCrashGuard::RecoverFromCrash()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
nsCOMPtr<nsIFile> file = GetGuardFile();
|
||||
bool exists;
|
||||
if ((file &&
|
||||
NS_SUCCEEDED(file->Exists(&exists)) &&
|
||||
exists) ||
|
||||
(GetStatus() == DriverInitStatus::Attempting))
|
||||
{
|
||||
// If we get here, we've just recovered from a crash. Disable acceleration
|
||||
// until the environment changes.
|
||||
if (file) {
|
||||
file->Remove(false);
|
||||
}
|
||||
NotifyCrashed();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true if the caller should proceed to guard for crashes. False if
|
||||
// the environment has not changed. We persist the "changed" status across
|
||||
// calls, so that after an environment changes, all guards for the new
|
||||
// session are activated rather than just the first.
|
||||
bool
|
||||
DriverCrashGuard::CheckOrRefreshEnvironment()
|
||||
{
|
||||
// Our result can be cached statically since we don't check live prefs.
|
||||
static bool sBaseInfoChanged = false;
|
||||
static bool sBaseInfoChecked = false;
|
||||
|
||||
if (!sBaseInfoChecked) {
|
||||
// None of the prefs we care about, so we cache the result statically.
|
||||
sBaseInfoChecked = true;
|
||||
sBaseInfoChanged = UpdateBaseEnvironment();
|
||||
}
|
||||
|
||||
// Always update the full environment, even if the base info didn't change.
|
||||
return UpdateEnvironment() ||
|
||||
sBaseInfoChanged ||
|
||||
GetStatus() == DriverInitStatus::Unknown;
|
||||
}
|
||||
|
||||
bool
|
||||
DriverCrashGuard::UpdateBaseEnvironment()
|
||||
{
|
||||
bool changed = false;
|
||||
if (mGfxInfo) {
|
||||
nsString value;
|
||||
|
||||
// Driver properties.
|
||||
mGfxInfo->GetAdapterDriverVersion(value);
|
||||
changed |= CheckAndUpdatePref("driverVersion", value);
|
||||
mGfxInfo->GetAdapterDeviceID(value);
|
||||
changed |= CheckAndUpdatePref("deviceID", value);
|
||||
}
|
||||
|
||||
// Firefox properties.
|
||||
changed |= CheckAndUpdatePref("appVersion", NS_LITERAL_STRING(MOZ_APP_VERSION));
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool
|
||||
DriverCrashGuard::FeatureEnabled(int aFeature, bool aDefault)
|
||||
{
|
||||
if (!mGfxInfo) {
|
||||
return aDefault;
|
||||
}
|
||||
int32_t status;
|
||||
nsCString discardFailureId;
|
||||
if (!NS_SUCCEEDED(mGfxInfo->GetFeatureStatus(aFeature, discardFailureId, &status))) {
|
||||
return false;
|
||||
}
|
||||
return status == nsIGfxInfo::FEATURE_STATUS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
DriverCrashGuard::CheckAndUpdateBoolPref(const char* aPrefName, bool aCurrentValue)
|
||||
{
|
||||
std::string pref = GetFullPrefName(aPrefName);
|
||||
|
||||
bool oldValue;
|
||||
if (NS_SUCCEEDED(Preferences::GetBool(pref.c_str(), &oldValue)) &&
|
||||
oldValue == aCurrentValue)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Preferences::SetBool(pref.c_str(), aCurrentValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DriverCrashGuard::CheckAndUpdatePref(const char* aPrefName, const nsAString& aCurrentValue)
|
||||
{
|
||||
std::string pref = GetFullPrefName(aPrefName);
|
||||
|
||||
nsAdoptingString oldValue = Preferences::GetString(pref.c_str());
|
||||
if (oldValue == aCurrentValue) {
|
||||
return false;
|
||||
}
|
||||
Preferences::SetString(pref.c_str(), aCurrentValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string
|
||||
DriverCrashGuard::GetFullPrefName(const char* aPref)
|
||||
{
|
||||
return std::string("gfx.crash-guard.") +
|
||||
std::string(sCrashGuardNames[uint32_t(mType)]) +
|
||||
std::string(".") +
|
||||
std::string(aPref);
|
||||
}
|
||||
|
||||
DriverInitStatus
|
||||
DriverCrashGuard::GetStatus() const
|
||||
{
|
||||
return (DriverInitStatus)Preferences::GetInt(mStatusPref.get(), 0);
|
||||
}
|
||||
|
||||
void
|
||||
DriverCrashGuard::SetStatus(DriverInitStatus aStatus)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
Preferences::SetInt(mStatusPref.get(), int32_t(aStatus));
|
||||
}
|
||||
|
||||
void
|
||||
DriverCrashGuard::FlushPreferences()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
if (nsIPrefService* prefService = Preferences::GetService()) {
|
||||
prefService->SavePrefFile(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DriverCrashGuard::ForEachActiveCrashGuard(const CrashGuardCallback& aCallback)
|
||||
{
|
||||
if (!AreCrashGuardsEnabled()) {
|
||||
// Even if guards look active (via prefs), they can be ignored if globally
|
||||
// disabled.
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < NUM_CRASH_GUARD_TYPES; i++) {
|
||||
CrashGuardType type = static_cast<CrashGuardType>(i);
|
||||
|
||||
nsCString prefName;
|
||||
BuildCrashGuardPrefName(type, prefName);
|
||||
|
||||
auto status =
|
||||
static_cast<DriverInitStatus>(Preferences::GetInt(prefName.get(), 0));
|
||||
if (status != DriverInitStatus::Crashed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
aCallback(sCrashGuardNames[i], prefName.get());
|
||||
}
|
||||
}
|
||||
|
||||
D3D11LayersCrashGuard::D3D11LayersCrashGuard(dom::ContentParent* aContentParent)
|
||||
: DriverCrashGuard(CrashGuardType::D3D11Layers, aContentParent)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
D3D11LayersCrashGuard::Initialize()
|
||||
{
|
||||
if (!XRE_IsParentProcess()) {
|
||||
// We assume the parent process already performed crash detection for
|
||||
// graphics devices.
|
||||
return;
|
||||
}
|
||||
|
||||
DriverCrashGuard::Initialize();
|
||||
|
||||
// If no telemetry states have been recorded, this will set the state to okay.
|
||||
// Otherwise, it will have no effect.
|
||||
RecordTelemetry(TelemetryState::Okay);
|
||||
}
|
||||
|
||||
bool
|
||||
D3D11LayersCrashGuard::UpdateEnvironment()
|
||||
{
|
||||
// Our result can be cached statically since we don't check live prefs.
|
||||
static bool checked = false;
|
||||
static bool changed = false;
|
||||
|
||||
if (checked) {
|
||||
return changed;
|
||||
}
|
||||
|
||||
checked = true;
|
||||
|
||||
// Feature status.
|
||||
#if defined(XP_WIN)
|
||||
bool d2dEnabled = gfxPrefs::Direct2DForceEnabled() ||
|
||||
(!gfxPrefs::Direct2DDisabled() && FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT2D));
|
||||
changed |= CheckAndUpdateBoolPref("feature-d2d", d2dEnabled);
|
||||
|
||||
bool d3d11Enabled = !gfxPrefs::LayersPreferD3D9();
|
||||
if (!FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS)) {
|
||||
d3d11Enabled = false;
|
||||
}
|
||||
changed |= CheckAndUpdateBoolPref("feature-d3d11", d3d11Enabled);
|
||||
#endif
|
||||
|
||||
if (!changed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RecordTelemetry(TelemetryState::EnvironmentChanged);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
D3D11LayersCrashGuard::LogCrashRecovery()
|
||||
{
|
||||
RecordTelemetry(TelemetryState::RecoveredFromCrash);
|
||||
gfxCriticalNote << "D3D11 layers just crashed; D3D11 will be disabled.";
|
||||
}
|
||||
|
||||
void
|
||||
D3D11LayersCrashGuard::LogFeatureDisabled()
|
||||
{
|
||||
RecordTelemetry(TelemetryState::FeatureDisabled);
|
||||
gfxCriticalNote << "D3D11 layers disabled due to a prior crash.";
|
||||
}
|
||||
|
||||
void
|
||||
D3D11LayersCrashGuard::RecordTelemetry(TelemetryState aState)
|
||||
{
|
||||
// D3D11LayersCrashGuard is a no-op in the child process.
|
||||
if (!XRE_IsParentProcess()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Since we instantiate this class more than once, make sure we only record
|
||||
// the first state (since that is really all we care about).
|
||||
static bool sTelemetryStateRecorded = false;
|
||||
if (sTelemetryStateRecorded) {
|
||||
return;
|
||||
}
|
||||
|
||||
Telemetry::Accumulate(Telemetry::GRAPHICS_DRIVER_STARTUP_TEST, int32_t(aState));
|
||||
sTelemetryStateRecorded = true;
|
||||
}
|
||||
|
||||
D3D9VideoCrashGuard::D3D9VideoCrashGuard(dom::ContentParent* aContentParent)
|
||||
: DriverCrashGuard(CrashGuardType::D3D9Video, aContentParent)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
D3D9VideoCrashGuard::UpdateEnvironment()
|
||||
{
|
||||
// We don't care about any extra preferences here.
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
D3D9VideoCrashGuard::LogCrashRecovery()
|
||||
{
|
||||
gfxCriticalNote << "DXVA2D3D9 just crashed; hardware video will be disabled.";
|
||||
}
|
||||
|
||||
void
|
||||
D3D9VideoCrashGuard::LogFeatureDisabled()
|
||||
{
|
||||
gfxCriticalNote << "DXVA2D3D9 video decoding is disabled due to a previous crash.";
|
||||
}
|
||||
|
||||
D3D11VideoCrashGuard::D3D11VideoCrashGuard(dom::ContentParent* aContentParent)
|
||||
: DriverCrashGuard(CrashGuardType::D3D11Video, aContentParent)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
D3D11VideoCrashGuard::UpdateEnvironment()
|
||||
{
|
||||
// We don't care about any extra preferences here.
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
D3D11VideoCrashGuard::LogCrashRecovery()
|
||||
{
|
||||
gfxCriticalNote << "DXVA2D3D11 just crashed; hardware video will be disabled.";
|
||||
}
|
||||
|
||||
void
|
||||
D3D11VideoCrashGuard::LogFeatureDisabled()
|
||||
{
|
||||
gfxCriticalNote << "DXVA2D3D11 video decoding is disabled due to a previous crash.";
|
||||
}
|
||||
|
||||
GLContextCrashGuard::GLContextCrashGuard(dom::ContentParent* aContentParent)
|
||||
: DriverCrashGuard(CrashGuardType::GLContext, aContentParent)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
GLContextCrashGuard::Initialize()
|
||||
{
|
||||
if (XRE_IsContentProcess()) {
|
||||
// Disable the GL crash guard in content processes, since we're not going
|
||||
// to lose the entire browser and we don't want to hinder WebGL availability.
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
// Disable the WebGL crash guard on Android - it doesn't use E10S, and
|
||||
// its drivers will essentially never change, so the crash guard could
|
||||
// permanently disable WebGL.
|
||||
return;
|
||||
#endif
|
||||
|
||||
DriverCrashGuard::Initialize();
|
||||
}
|
||||
|
||||
bool
|
||||
GLContextCrashGuard::UpdateEnvironment()
|
||||
{
|
||||
static bool checked = false;
|
||||
static bool changed = false;
|
||||
|
||||
if (checked) {
|
||||
return changed;
|
||||
}
|
||||
|
||||
checked = true;
|
||||
|
||||
#if defined(XP_WIN)
|
||||
changed |= CheckAndUpdateBoolPref("gfx.driver-init.webgl-angle-force-d3d11",
|
||||
gfxPrefs::WebGLANGLEForceD3D11());
|
||||
changed |= CheckAndUpdateBoolPref("gfx.driver-init.webgl-angle-try-d3d11",
|
||||
gfxPrefs::WebGLANGLETryD3D11());
|
||||
changed |= CheckAndUpdateBoolPref("gfx.driver-init.webgl-angle-force-warp",
|
||||
gfxPrefs::WebGLANGLEForceWARP());
|
||||
changed |= CheckAndUpdateBoolPref("gfx.driver-init.webgl-angle",
|
||||
FeatureEnabled(nsIGfxInfo::FEATURE_WEBGL_ANGLE, false));
|
||||
changed |= CheckAndUpdateBoolPref("gfx.driver-init.direct3d11-angle",
|
||||
FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE, false));
|
||||
#endif
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
void
|
||||
GLContextCrashGuard::LogCrashRecovery()
|
||||
{
|
||||
gfxCriticalNote << "GLContext just crashed.";
|
||||
}
|
||||
|
||||
void
|
||||
GLContextCrashGuard::LogFeatureDisabled()
|
||||
{
|
||||
gfxCriticalNote << "GLContext remains enabled despite a previous crash.";
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
182
gfx/src/DriverCrashGuard.h
Normal file
182
gfx/src/DriverCrashGuard.h
Normal 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/. */
|
||||
#ifndef gfx_src_DriverCrashGuard_h__
|
||||
#define gfx_src_DriverCrashGuard_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIGfxInfo.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/Function.h"
|
||||
#include <string>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class ContentParent;
|
||||
} // namespace dom
|
||||
|
||||
namespace gfx {
|
||||
|
||||
enum class DriverInitStatus
|
||||
{
|
||||
// Drivers have not been initialized yet.
|
||||
Unknown,
|
||||
|
||||
// We're attempting to initialize drivers.
|
||||
Attempting,
|
||||
|
||||
// Drivers were successfully initialized last run.
|
||||
Okay,
|
||||
|
||||
// We crashed during driver initialization, and have restarted.
|
||||
Crashed
|
||||
};
|
||||
|
||||
enum class CrashGuardType : uint32_t
|
||||
{
|
||||
D3D11Layers,
|
||||
D3D9Video,
|
||||
GLContext,
|
||||
D3D11Video,
|
||||
// Add new entries above this line, update the name array in
|
||||
// DriverCrashGuard.cpp, and make sure to add an entry in
|
||||
// ContentParent.cpp.
|
||||
|
||||
NUM_TYPES
|
||||
};
|
||||
|
||||
// DriverCrashGuard is used to detect crashes at graphics driver callsites.
|
||||
//
|
||||
// If the graphics environment is unrecognized or has changed since the last
|
||||
// session, the crash guard will activate and will detect any crashes within
|
||||
// the scope of the guard object.
|
||||
//
|
||||
// If a callsite has a previously encountered crash, and the environment has
|
||||
// not changed since the last session, then the guard will set a status flag
|
||||
// indicating that the driver should not be used.
|
||||
class DriverCrashGuard
|
||||
{
|
||||
public:
|
||||
DriverCrashGuard(CrashGuardType aType, dom::ContentParent* aContentParent);
|
||||
virtual ~DriverCrashGuard();
|
||||
|
||||
bool Crashed();
|
||||
void NotifyCrashed();
|
||||
|
||||
// These are the values reported to Telemetry (GRAPHICS_DRIVER_STARTUP_TEST).
|
||||
// Values should not change; add new values to the end.
|
||||
enum class TelemetryState {
|
||||
Okay = 0,
|
||||
EnvironmentChanged = 1,
|
||||
RecoveredFromCrash = 2,
|
||||
FeatureDisabled = 3
|
||||
};
|
||||
|
||||
enum class Mode {
|
||||
// Normal operation.
|
||||
Normal,
|
||||
|
||||
// Acting as a proxy between the parent and child process.
|
||||
Proxy
|
||||
};
|
||||
|
||||
typedef mozilla::function<void(const char* aName, const char* aPrefName)>
|
||||
CrashGuardCallback;
|
||||
static void ForEachActiveCrashGuard(const CrashGuardCallback& aCallback);
|
||||
|
||||
protected:
|
||||
virtual void Initialize();
|
||||
virtual bool UpdateEnvironment() = 0;
|
||||
virtual void LogCrashRecovery() = 0;
|
||||
virtual void LogFeatureDisabled() = 0;
|
||||
|
||||
// Helper functions.
|
||||
bool FeatureEnabled(int aFeature, bool aDefault=true);
|
||||
bool CheckAndUpdatePref(const char* aPrefName, const nsAString& aCurrentValue);
|
||||
bool CheckAndUpdateBoolPref(const char* aPrefName, bool aCurrentValue);
|
||||
std::string GetFullPrefName(const char* aPref);
|
||||
|
||||
private:
|
||||
// Either process.
|
||||
void InitializeIfNeeded();
|
||||
bool CheckOrRefreshEnvironment();
|
||||
bool UpdateBaseEnvironment();
|
||||
DriverInitStatus GetStatus() const;
|
||||
|
||||
// Parent process only.
|
||||
nsCOMPtr<nsIFile> GetGuardFile();
|
||||
bool RecoverFromCrash();
|
||||
void ActivateGuard();
|
||||
void FlushPreferences();
|
||||
void SetStatus(DriverInitStatus aStatus);
|
||||
|
||||
private:
|
||||
CrashGuardType mType;
|
||||
Mode mMode;
|
||||
bool mInitialized;
|
||||
bool mGuardActivated;
|
||||
bool mCrashDetected;
|
||||
nsCOMPtr<nsIFile> mGuardFile;
|
||||
|
||||
protected:
|
||||
nsCString mStatusPref;
|
||||
nsCOMPtr<nsIGfxInfo> mGfxInfo;
|
||||
};
|
||||
|
||||
class D3D11LayersCrashGuard final : public DriverCrashGuard
|
||||
{
|
||||
public:
|
||||
explicit D3D11LayersCrashGuard(dom::ContentParent* aContentParent = nullptr);
|
||||
|
||||
protected:
|
||||
void Initialize() override;
|
||||
bool UpdateEnvironment() override;
|
||||
void LogCrashRecovery() override;
|
||||
void LogFeatureDisabled() override;
|
||||
|
||||
private:
|
||||
void RecordTelemetry(TelemetryState aState);
|
||||
};
|
||||
|
||||
class D3D9VideoCrashGuard final : public DriverCrashGuard
|
||||
{
|
||||
public:
|
||||
explicit D3D9VideoCrashGuard(dom::ContentParent* aContentParent = nullptr);
|
||||
|
||||
protected:
|
||||
bool UpdateEnvironment() override;
|
||||
void LogCrashRecovery() override;
|
||||
void LogFeatureDisabled() override;
|
||||
};
|
||||
|
||||
class D3D11VideoCrashGuard final : public DriverCrashGuard
|
||||
{
|
||||
public:
|
||||
explicit D3D11VideoCrashGuard(dom::ContentParent* aContentParent = nullptr);
|
||||
|
||||
protected:
|
||||
bool UpdateEnvironment() override;
|
||||
void LogCrashRecovery() override;
|
||||
void LogFeatureDisabled() override;
|
||||
};
|
||||
|
||||
class GLContextCrashGuard final : public DriverCrashGuard
|
||||
{
|
||||
public:
|
||||
explicit GLContextCrashGuard(dom::ContentParent* aContentParent = nullptr);
|
||||
void Initialize() override;
|
||||
|
||||
protected:
|
||||
bool UpdateEnvironment() override;
|
||||
void LogCrashRecovery() override;
|
||||
void LogFeatureDisabled() override;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // gfx_src_DriverCrashGuard_h__
|
||||
|
||||
2185
gfx/src/FilterSupport.cpp
Normal file
2185
gfx/src/FilterSupport.cpp
Normal file
File diff suppressed because it is too large
Load diff
479
gfx/src/FilterSupport.h
Normal file
479
gfx/src/FilterSupport.h
Normal file
|
|
@ -0,0 +1,479 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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 __FilterSupport_h
|
||||
#define __FilterSupport_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/gfx/Rect.h"
|
||||
#include "mozilla/gfx/Matrix.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsRegion.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
// Morphology Operators
|
||||
const unsigned short SVG_OPERATOR_UNKNOWN = 0;
|
||||
const unsigned short SVG_OPERATOR_ERODE = 1;
|
||||
const unsigned short SVG_OPERATOR_DILATE = 2;
|
||||
|
||||
// ColorMatrix types
|
||||
const unsigned short SVG_FECOLORMATRIX_TYPE_UNKNOWN = 0;
|
||||
const unsigned short SVG_FECOLORMATRIX_TYPE_MATRIX = 1;
|
||||
const unsigned short SVG_FECOLORMATRIX_TYPE_SATURATE = 2;
|
||||
const unsigned short SVG_FECOLORMATRIX_TYPE_HUE_ROTATE = 3;
|
||||
const unsigned short SVG_FECOLORMATRIX_TYPE_LUMINANCE_TO_ALPHA = 4;
|
||||
// ColorMatrix types for CSS filters
|
||||
const unsigned short SVG_FECOLORMATRIX_TYPE_SEPIA = 5;
|
||||
|
||||
// ComponentTransfer types
|
||||
const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_UNKNOWN = 0;
|
||||
const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY = 1;
|
||||
const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_TABLE = 2;
|
||||
const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE = 3;
|
||||
const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_LINEAR = 4;
|
||||
const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_GAMMA = 5;
|
||||
|
||||
// Blend Mode Values
|
||||
const unsigned short SVG_FEBLEND_MODE_UNKNOWN = 0;
|
||||
const unsigned short SVG_FEBLEND_MODE_NORMAL = 1;
|
||||
const unsigned short SVG_FEBLEND_MODE_MULTIPLY = 2;
|
||||
const unsigned short SVG_FEBLEND_MODE_SCREEN = 3;
|
||||
const unsigned short SVG_FEBLEND_MODE_DARKEN = 4;
|
||||
const unsigned short SVG_FEBLEND_MODE_LIGHTEN = 5;
|
||||
const unsigned short SVG_FEBLEND_MODE_OVERLAY = 6;
|
||||
const unsigned short SVG_FEBLEND_MODE_COLOR_DODGE = 7;
|
||||
const unsigned short SVG_FEBLEND_MODE_COLOR_BURN = 8;
|
||||
const unsigned short SVG_FEBLEND_MODE_HARD_LIGHT = 9;
|
||||
const unsigned short SVG_FEBLEND_MODE_SOFT_LIGHT = 10;
|
||||
const unsigned short SVG_FEBLEND_MODE_DIFFERENCE = 11;
|
||||
const unsigned short SVG_FEBLEND_MODE_EXCLUSION = 12;
|
||||
const unsigned short SVG_FEBLEND_MODE_HUE = 13;
|
||||
const unsigned short SVG_FEBLEND_MODE_SATURATION = 14;
|
||||
const unsigned short SVG_FEBLEND_MODE_COLOR = 15;
|
||||
const unsigned short SVG_FEBLEND_MODE_LUMINOSITY = 16;
|
||||
|
||||
// Edge Mode Values
|
||||
const unsigned short SVG_EDGEMODE_UNKNOWN = 0;
|
||||
const unsigned short SVG_EDGEMODE_DUPLICATE = 1;
|
||||
const unsigned short SVG_EDGEMODE_WRAP = 2;
|
||||
const unsigned short SVG_EDGEMODE_NONE = 3;
|
||||
|
||||
// Channel Selectors
|
||||
const unsigned short SVG_CHANNEL_UNKNOWN = 0;
|
||||
const unsigned short SVG_CHANNEL_R = 1;
|
||||
const unsigned short SVG_CHANNEL_G = 2;
|
||||
const unsigned short SVG_CHANNEL_B = 3;
|
||||
const unsigned short SVG_CHANNEL_A = 4;
|
||||
|
||||
// Turbulence Types
|
||||
const unsigned short SVG_TURBULENCE_TYPE_UNKNOWN = 0;
|
||||
const unsigned short SVG_TURBULENCE_TYPE_FRACTALNOISE = 1;
|
||||
const unsigned short SVG_TURBULENCE_TYPE_TURBULENCE = 2;
|
||||
|
||||
// Composite Operators
|
||||
const unsigned short SVG_FECOMPOSITE_OPERATOR_UNKNOWN = 0;
|
||||
const unsigned short SVG_FECOMPOSITE_OPERATOR_OVER = 1;
|
||||
const unsigned short SVG_FECOMPOSITE_OPERATOR_IN = 2;
|
||||
const unsigned short SVG_FECOMPOSITE_OPERATOR_OUT = 3;
|
||||
const unsigned short SVG_FECOMPOSITE_OPERATOR_ATOP = 4;
|
||||
const unsigned short SVG_FECOMPOSITE_OPERATOR_XOR = 5;
|
||||
const unsigned short SVG_FECOMPOSITE_OPERATOR_ARITHMETIC = 6;
|
||||
|
||||
enum AttributeName {
|
||||
eBlendBlendmode = 0,
|
||||
eMorphologyRadii,
|
||||
eMorphologyOperator,
|
||||
eColorMatrixType,
|
||||
eColorMatrixValues,
|
||||
eFloodColor,
|
||||
eTileSourceRect,
|
||||
eComponentTransferFunctionR,
|
||||
eComponentTransferFunctionG,
|
||||
eComponentTransferFunctionB,
|
||||
eComponentTransferFunctionA,
|
||||
eComponentTransferFunctionType,
|
||||
eComponentTransferFunctionTableValues,
|
||||
eComponentTransferFunctionSlope,
|
||||
eComponentTransferFunctionIntercept,
|
||||
eComponentTransferFunctionAmplitude,
|
||||
eComponentTransferFunctionExponent,
|
||||
eComponentTransferFunctionOffset,
|
||||
eConvolveMatrixKernelSize,
|
||||
eConvolveMatrixKernelMatrix,
|
||||
eConvolveMatrixDivisor,
|
||||
eConvolveMatrixBias,
|
||||
eConvolveMatrixTarget,
|
||||
eConvolveMatrixEdgeMode,
|
||||
eConvolveMatrixKernelUnitLength,
|
||||
eConvolveMatrixPreserveAlpha,
|
||||
eOffsetOffset,
|
||||
eDropShadowStdDeviation,
|
||||
eDropShadowOffset,
|
||||
eDropShadowColor,
|
||||
eDisplacementMapScale,
|
||||
eDisplacementMapXChannel,
|
||||
eDisplacementMapYChannel,
|
||||
eTurbulenceOffset,
|
||||
eTurbulenceBaseFrequency,
|
||||
eTurbulenceNumOctaves,
|
||||
eTurbulenceSeed,
|
||||
eTurbulenceStitchable,
|
||||
eTurbulenceType,
|
||||
eCompositeOperator,
|
||||
eCompositeCoefficients,
|
||||
eGaussianBlurStdDeviation,
|
||||
eLightingLight,
|
||||
eLightingSurfaceScale,
|
||||
eLightingKernelUnitLength,
|
||||
eLightingColor,
|
||||
eDiffuseLightingDiffuseConstant,
|
||||
eSpecularLightingSpecularConstant,
|
||||
eSpecularLightingSpecularExponent,
|
||||
eLightType,
|
||||
eLightTypeNone,
|
||||
eLightTypePoint,
|
||||
eLightTypeSpot,
|
||||
eLightTypeDistant,
|
||||
ePointLightPosition,
|
||||
eSpotLightPosition,
|
||||
eSpotLightPointsAt,
|
||||
eSpotLightFocus,
|
||||
eSpotLightLimitingConeAngle,
|
||||
eDistantLightAzimuth,
|
||||
eDistantLightElevation,
|
||||
eImageInputIndex,
|
||||
eImageFilter,
|
||||
eImageNativeSize,
|
||||
eImageSubregion,
|
||||
eImageTransform,
|
||||
eLastAttributeName
|
||||
};
|
||||
|
||||
class DrawTarget;
|
||||
class SourceSurface;
|
||||
struct FilterAttribute;
|
||||
|
||||
enum class AttributeType {
|
||||
eBool,
|
||||
eUint,
|
||||
eFloat,
|
||||
eSize,
|
||||
eIntSize,
|
||||
eIntPoint,
|
||||
eMatrix,
|
||||
eMatrix5x4,
|
||||
ePoint3D,
|
||||
eColor,
|
||||
eAttributeMap,
|
||||
eFloats,
|
||||
Max
|
||||
};
|
||||
|
||||
// Limits
|
||||
const float kMaxStdDeviation = 500;
|
||||
|
||||
// A class that stores values of different types, keyed by an attribute name.
|
||||
// The Get*() methods assert that they're called for the same type that the
|
||||
// attribute was Set() with.
|
||||
// AttributeMaps can be nested because AttributeMap is a valid attribute type.
|
||||
class AttributeMap final {
|
||||
public:
|
||||
AttributeMap();
|
||||
AttributeMap(const AttributeMap& aOther);
|
||||
AttributeMap& operator=(const AttributeMap& aOther);
|
||||
bool operator==(const AttributeMap& aOther) const;
|
||||
bool operator!=(const AttributeMap& aOther) const
|
||||
{
|
||||
return !(*this == aOther);
|
||||
}
|
||||
~AttributeMap();
|
||||
|
||||
void Set(AttributeName aName, bool aValue);
|
||||
void Set(AttributeName aName, uint32_t aValue);
|
||||
void Set(AttributeName aName, float aValue);
|
||||
void Set(AttributeName aName, const Size& aValue);
|
||||
void Set(AttributeName aName, const IntSize& aValue);
|
||||
void Set(AttributeName aName, const IntPoint& aValue);
|
||||
void Set(AttributeName aName, const Matrix& aValue);
|
||||
void Set(AttributeName aName, const Matrix5x4& aValue);
|
||||
void Set(AttributeName aName, const Point3D& aValue);
|
||||
void Set(AttributeName aName, const Color& aValue);
|
||||
void Set(AttributeName aName, const AttributeMap& aValue);
|
||||
void Set(AttributeName aName, const float* aValues, int32_t aLength);
|
||||
|
||||
bool GetBool(AttributeName aName) const;
|
||||
uint32_t GetUint(AttributeName aName) const;
|
||||
float GetFloat(AttributeName aName) const;
|
||||
Size GetSize(AttributeName aName) const;
|
||||
IntSize GetIntSize(AttributeName aName) const;
|
||||
IntPoint GetIntPoint(AttributeName aName) const;
|
||||
Matrix GetMatrix(AttributeName aName) const;
|
||||
Matrix5x4 GetMatrix5x4(AttributeName aName) const;
|
||||
Point3D GetPoint3D(AttributeName aName) const;
|
||||
Color GetColor(AttributeName aName) const;
|
||||
AttributeMap GetAttributeMap(AttributeName aName) const;
|
||||
const nsTArray<float>& GetFloats(AttributeName aName) const;
|
||||
|
||||
uint32_t Count() const;
|
||||
|
||||
nsClassHashtable<nsUint32HashKey, FilterAttribute>::Iterator ConstIter() const;
|
||||
|
||||
static AttributeType GetType(FilterAttribute* aAttribute);
|
||||
|
||||
private:
|
||||
mutable nsClassHashtable<nsUint32HashKey, FilterAttribute> mMap;
|
||||
};
|
||||
|
||||
enum class ColorSpace {
|
||||
SRGB,
|
||||
LinearRGB,
|
||||
Max
|
||||
};
|
||||
|
||||
enum class AlphaModel {
|
||||
Unpremultiplied,
|
||||
Premultiplied
|
||||
};
|
||||
|
||||
class ColorModel {
|
||||
public:
|
||||
static ColorModel PremulSRGB()
|
||||
{
|
||||
return ColorModel(ColorSpace::SRGB, AlphaModel::Premultiplied);
|
||||
}
|
||||
|
||||
ColorModel(ColorSpace aColorSpace, AlphaModel aAlphaModel) :
|
||||
mColorSpace(aColorSpace), mAlphaModel(aAlphaModel) {}
|
||||
ColorModel() :
|
||||
mColorSpace(ColorSpace::SRGB), mAlphaModel(AlphaModel::Premultiplied) {}
|
||||
bool operator==(const ColorModel& aOther) const {
|
||||
return mColorSpace == aOther.mColorSpace &&
|
||||
mAlphaModel == aOther.mAlphaModel;
|
||||
}
|
||||
|
||||
// Used to index FilterCachedColorModels::mFilterForColorModel.
|
||||
uint8_t ToIndex() const
|
||||
{
|
||||
return (uint8_t(mColorSpace) << 1) + uint8_t(mAlphaModel);
|
||||
}
|
||||
|
||||
ColorSpace mColorSpace;
|
||||
AlphaModel mAlphaModel;
|
||||
};
|
||||
|
||||
enum class PrimitiveType {
|
||||
Empty = 0,
|
||||
Blend,
|
||||
Morphology,
|
||||
ColorMatrix,
|
||||
Flood,
|
||||
Tile,
|
||||
ComponentTransfer,
|
||||
ConvolveMatrix,
|
||||
Offset,
|
||||
DisplacementMap,
|
||||
Turbulence,
|
||||
Composite,
|
||||
Merge,
|
||||
Image,
|
||||
GaussianBlur,
|
||||
DropShadow,
|
||||
DiffuseLighting,
|
||||
SpecularLighting,
|
||||
ToAlpha,
|
||||
Max
|
||||
};
|
||||
|
||||
/**
|
||||
* A data structure to carry attributes for a given primitive that's part of a
|
||||
* filter. Will be serializable via IPDL, so it must not contain complex
|
||||
* functionality.
|
||||
* Used as part of a FilterDescription.
|
||||
*/
|
||||
class FilterPrimitiveDescription final {
|
||||
public:
|
||||
enum {
|
||||
kPrimitiveIndexSourceGraphic = -1,
|
||||
kPrimitiveIndexSourceAlpha = -2,
|
||||
kPrimitiveIndexFillPaint = -3,
|
||||
kPrimitiveIndexStrokePaint = -4
|
||||
};
|
||||
|
||||
FilterPrimitiveDescription();
|
||||
explicit FilterPrimitiveDescription(PrimitiveType aType);
|
||||
FilterPrimitiveDescription(const FilterPrimitiveDescription& aOther);
|
||||
FilterPrimitiveDescription& operator=(const FilterPrimitiveDescription& aOther);
|
||||
|
||||
PrimitiveType Type() const { return mType; }
|
||||
void SetType(PrimitiveType aType) { mType = aType; }
|
||||
const AttributeMap& Attributes() const { return mAttributes; }
|
||||
AttributeMap& Attributes() { return mAttributes; }
|
||||
|
||||
IntRect PrimitiveSubregion() const { return mFilterPrimitiveSubregion; }
|
||||
IntRect FilterSpaceBounds() const { return mFilterSpaceBounds; }
|
||||
bool IsTainted() const { return mIsTainted; }
|
||||
|
||||
size_t NumberOfInputs() const { return mInputPrimitives.Length(); }
|
||||
int32_t InputPrimitiveIndex(size_t aInputIndex) const
|
||||
{
|
||||
return aInputIndex < mInputPrimitives.Length() ?
|
||||
mInputPrimitives[aInputIndex] : 0;
|
||||
}
|
||||
|
||||
ColorSpace InputColorSpace(size_t aInputIndex) const
|
||||
{
|
||||
return aInputIndex < mInputColorSpaces.Length() ?
|
||||
mInputColorSpaces[aInputIndex] : ColorSpace();
|
||||
}
|
||||
|
||||
ColorSpace OutputColorSpace() const { return mOutputColorSpace; }
|
||||
|
||||
void SetPrimitiveSubregion(const IntRect& aRect)
|
||||
{
|
||||
mFilterPrimitiveSubregion = aRect;
|
||||
}
|
||||
|
||||
void SetFilterSpaceBounds(const IntRect& aRect)
|
||||
{
|
||||
mFilterSpaceBounds = aRect;
|
||||
}
|
||||
|
||||
void SetIsTainted(bool aIsTainted)
|
||||
{
|
||||
mIsTainted = aIsTainted;
|
||||
}
|
||||
|
||||
void SetInputPrimitive(size_t aInputIndex, int32_t aInputPrimitiveIndex)
|
||||
{
|
||||
mInputPrimitives.EnsureLengthAtLeast(aInputIndex + 1);
|
||||
mInputPrimitives[aInputIndex] = aInputPrimitiveIndex;
|
||||
}
|
||||
|
||||
void SetInputColorSpace(size_t aInputIndex, ColorSpace aColorSpace)
|
||||
{
|
||||
mInputColorSpaces.EnsureLengthAtLeast(aInputIndex + 1);
|
||||
mInputColorSpaces[aInputIndex] = aColorSpace;
|
||||
}
|
||||
|
||||
void SetOutputColorSpace(const ColorSpace& aColorSpace)
|
||||
{
|
||||
mOutputColorSpace = aColorSpace;
|
||||
}
|
||||
|
||||
bool operator==(const FilterPrimitiveDescription& aOther) const;
|
||||
bool operator!=(const FilterPrimitiveDescription& aOther) const
|
||||
{
|
||||
return !(*this == aOther);
|
||||
}
|
||||
|
||||
private:
|
||||
PrimitiveType mType;
|
||||
AttributeMap mAttributes;
|
||||
nsTArray<int32_t> mInputPrimitives;
|
||||
IntRect mFilterPrimitiveSubregion;
|
||||
IntRect mFilterSpaceBounds;
|
||||
nsTArray<ColorSpace> mInputColorSpaces;
|
||||
ColorSpace mOutputColorSpace;
|
||||
bool mIsTainted;
|
||||
};
|
||||
|
||||
/**
|
||||
* A data structure that contains one or more FilterPrimitiveDescriptions.
|
||||
* Designed to be serializable via IPDL, so it must not contain complex
|
||||
* functionality.
|
||||
*/
|
||||
struct FilterDescription final {
|
||||
FilterDescription() {}
|
||||
explicit FilterDescription(const nsTArray<FilterPrimitiveDescription>& aPrimitives)
|
||||
: mPrimitives(aPrimitives)
|
||||
{}
|
||||
|
||||
bool operator==(const FilterDescription& aOther) const;
|
||||
bool operator!=(const FilterDescription& aOther) const
|
||||
{
|
||||
return !(*this == aOther);
|
||||
}
|
||||
|
||||
nsTArray<FilterPrimitiveDescription> mPrimitives;
|
||||
};
|
||||
|
||||
/**
|
||||
* The methods of this class are not on FilterDescription because
|
||||
* FilterDescription is designed as a simple value holder that can be used
|
||||
* on any thread.
|
||||
*/
|
||||
class FilterSupport {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Draw the filter described by aFilter. All rect parameters are in filter
|
||||
* space coordinates. aRenderRect specifies the part of the filter output
|
||||
* that will be drawn at (0, 0) into the draw target aDT, subject to the
|
||||
* current transform on aDT but with no additional scaling.
|
||||
* The source surfaces must match their corresponding rect in size.
|
||||
* aAdditionalImages carries the images that are referenced by the
|
||||
* eImageInputIndex attribute on any image primitives in the filter.
|
||||
*/
|
||||
static void
|
||||
RenderFilterDescription(DrawTarget* aDT,
|
||||
const FilterDescription& aFilter,
|
||||
const Rect& aRenderRect,
|
||||
SourceSurface* aSourceGraphic,
|
||||
const IntRect& aSourceGraphicRect,
|
||||
SourceSurface* aFillPaint,
|
||||
const IntRect& aFillPaintRect,
|
||||
SourceSurface* aStrokePaint,
|
||||
const IntRect& aStrokePaintRect,
|
||||
nsTArray<RefPtr<SourceSurface>>& aAdditionalImages,
|
||||
const Point& aDestPoint,
|
||||
const DrawOptions& aOptions = DrawOptions());
|
||||
|
||||
/**
|
||||
* Computes the region that changes in the filter output due to a change in
|
||||
* input. This is primarily needed when an individual piece of content inside
|
||||
* a filtered container element changes.
|
||||
*/
|
||||
static nsIntRegion
|
||||
ComputeResultChangeRegion(const FilterDescription& aFilter,
|
||||
const nsIntRegion& aSourceGraphicChange,
|
||||
const nsIntRegion& aFillPaintChange,
|
||||
const nsIntRegion& aStrokePaintChange);
|
||||
|
||||
/**
|
||||
* Computes the regions that need to be supplied in the filter inputs when
|
||||
* painting aResultNeededRegion of the filter output.
|
||||
*/
|
||||
static void
|
||||
ComputeSourceNeededRegions(const FilterDescription& aFilter,
|
||||
const nsIntRegion& aResultNeededRegion,
|
||||
nsIntRegion& aSourceGraphicNeededRegion,
|
||||
nsIntRegion& aFillPaintNeededRegion,
|
||||
nsIntRegion& aStrokePaintNeededRegion);
|
||||
|
||||
/**
|
||||
* Computes the size of the filter output.
|
||||
*/
|
||||
static nsIntRegion
|
||||
ComputePostFilterExtents(const FilterDescription& aFilter,
|
||||
const nsIntRegion& aSourceGraphicExtents);
|
||||
|
||||
/**
|
||||
* Computes the size of a single FilterPrimitiveDescription's output given a
|
||||
* set of input extents.
|
||||
*/
|
||||
static nsIntRegion
|
||||
PostFilterExtentsForPrimitive(const FilterPrimitiveDescription& aDescription,
|
||||
const nsTArray<nsIntRegion>& aInputExtents);
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // __FilterSupport_h
|
||||
63
gfx/src/PingPongRegion.h
Normal file
63
gfx/src/PingPongRegion.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/* -*- 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 PingPongRegion_h__
|
||||
#define PingPongRegion_h__
|
||||
|
||||
/* This class uses a pair of regions and swaps between them while
|
||||
* accumulating to avoid the heap allocations associated with
|
||||
* modifying a region in place.
|
||||
*
|
||||
* It is sizeof(T)*2 + sizeof(T*) and can use end up using
|
||||
* approximately double the amount of memory as using single
|
||||
* region so use it sparingly.
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
class PingPongRegion
|
||||
{
|
||||
typedef typename T::RectType RectType;
|
||||
public:
|
||||
PingPongRegion()
|
||||
{
|
||||
rgn = &rgn1;
|
||||
}
|
||||
|
||||
void SubOut(const RectType& aOther)
|
||||
{
|
||||
T* nextRgn = nextRegion();
|
||||
nextRgn->Sub(*rgn, aOther);
|
||||
rgn = nextRgn;
|
||||
}
|
||||
|
||||
void OrWith(const RectType& aOther)
|
||||
{
|
||||
T* nextRgn = nextRegion();
|
||||
nextRgn->Or(*rgn, aOther);
|
||||
rgn = nextRgn;
|
||||
}
|
||||
|
||||
T& Region()
|
||||
{
|
||||
return *rgn;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
T* nextRegion()
|
||||
{
|
||||
if (rgn == &rgn1) {
|
||||
return &rgn2;
|
||||
} else {
|
||||
return &rgn1;
|
||||
}
|
||||
}
|
||||
|
||||
T* rgn;
|
||||
T rgn1;
|
||||
T rgn2;
|
||||
};
|
||||
|
||||
#endif
|
||||
32
gfx/src/RegionBuilder.h
Normal file
32
gfx/src/RegionBuilder.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/* 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 RegionBuilder_h__
|
||||
#define RegionBuilder_h__
|
||||
|
||||
#include <nsTArray.h>
|
||||
|
||||
template <typename RegionType>
|
||||
class RegionBuilder
|
||||
{
|
||||
public:
|
||||
typedef typename RegionType::RectType RectType;
|
||||
|
||||
RegionBuilder()
|
||||
{}
|
||||
|
||||
void OrWith(const RectType& aRect) {
|
||||
pixman_box32_t box = { aRect.x, aRect.y, aRect.XMost(), aRect.YMost() };
|
||||
mRects.AppendElement(box);
|
||||
}
|
||||
|
||||
RegionType ToRegion() const {
|
||||
return RegionType(mRects);
|
||||
}
|
||||
|
||||
private:
|
||||
nsTArray<pixman_box32_t> mRects;
|
||||
};
|
||||
|
||||
#endif // RegionBuilder_h__
|
||||
370
gfx/src/TiledRegion.cpp
Normal file
370
gfx/src/TiledRegion.cpp
Normal file
|
|
@ -0,0 +1,370 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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/. */
|
||||
|
||||
#include "TiledRegion.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "mozilla/fallible.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
static const int32_t kTileSize = 256;
|
||||
static const size_t kMaxTiles = 1000;
|
||||
|
||||
/**
|
||||
* TiledRegionImpl stores an array of non-empty rectangles (pixman_box32_ts) to
|
||||
* represent the region. Each rectangle is contained in a single tile;
|
||||
* rectangles never cross tile boundaries. The rectangles are sorted by their
|
||||
* tile's origin in top-to-bottom, left-to-right order.
|
||||
* (Note that this can mean that a rectangle r1 can come before another
|
||||
* rectangle r2 even if r2.y1 < r1.y1, as long as the two rects are in the same
|
||||
* row of tiles and r1.x1 < r2.x1.)
|
||||
* Empty tiles take up no space in the array - there is no rectangle stored for
|
||||
* them. As a result, any algorithm that needs to deal with empty tiles will
|
||||
* iterate through the mRects array and compare the positions of two
|
||||
* consecutive rects to figure out whether there are any empty tiles between
|
||||
* them.
|
||||
*/
|
||||
|
||||
static pixman_box32_t
|
||||
IntersectionOfNonEmptyBoxes(const pixman_box32_t& aBox1,
|
||||
const pixman_box32_t& aBox2)
|
||||
{
|
||||
return pixman_box32_t {
|
||||
std::max(aBox1.x1, aBox2.x1),
|
||||
std::max(aBox1.y1, aBox2.y1),
|
||||
std::min(aBox1.x2, aBox2.x2),
|
||||
std::min(aBox1.y2, aBox2.y2)
|
||||
};
|
||||
}
|
||||
|
||||
// A TileIterator points to a specific tile inside a certain tile range, or to
|
||||
// the end of the tile range. Advancing a TileIterator will move to the next
|
||||
// tile inside the range (or to the range end). The next tile is either the
|
||||
// tile to the right of the current one, or the first tile of the next tile
|
||||
// row if the current tile is already the last tile in the row.
|
||||
class TileIterator {
|
||||
public:
|
||||
TileIterator(const pixman_box32_t& aTileBounds, const IntPoint& aPosition)
|
||||
: mTileBounds(aTileBounds)
|
||||
, mPos(aPosition)
|
||||
{}
|
||||
|
||||
bool operator!=(const TileIterator& aOther) { return mPos != aOther.mPos; }
|
||||
bool operator==(const TileIterator& aOther) { return mPos == aOther.mPos; }
|
||||
|
||||
IntPoint operator*() const { return mPos; }
|
||||
|
||||
const TileIterator& operator++() {
|
||||
mPos.x += kTileSize;
|
||||
if (mPos.x >= mTileBounds.x2) {
|
||||
mPos.x = mTileBounds.x1;
|
||||
mPos.y += kTileSize;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
TileIterator& operator=(const IntPoint& aPosition)
|
||||
{
|
||||
mPos = aPosition;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool IsBeforeTileContainingPoint(const IntPoint& aPoint) const
|
||||
{
|
||||
return (mPos.y + kTileSize) <= aPoint.y ||
|
||||
(mPos.y <= aPoint.y && (mPos.x + kTileSize) <= aPoint.x);
|
||||
}
|
||||
|
||||
bool IsAtTileContainingPoint(const IntPoint& aPoint) const
|
||||
{
|
||||
return mPos.y <= aPoint.y && aPoint.y < (mPos.y + kTileSize) &&
|
||||
mPos.x <= aPoint.x && aPoint.x < (mPos.x + kTileSize);
|
||||
|
||||
}
|
||||
|
||||
pixman_box32_t IntersectionWith(const pixman_box32_t& aRect) const
|
||||
{
|
||||
pixman_box32_t tile = { mPos.x, mPos.y,
|
||||
mPos.x + kTileSize, mPos.y + kTileSize };
|
||||
return IntersectionOfNonEmptyBoxes(tile, aRect);
|
||||
}
|
||||
|
||||
private:
|
||||
const pixman_box32_t& mTileBounds;
|
||||
IntPoint mPos;
|
||||
};
|
||||
|
||||
// A TileRange describes a range of tiles contained inside a certain tile
|
||||
// bounds (which is a rectangle that includes all tiles that you're
|
||||
// interested in). The tile range can start and end at any point inside a
|
||||
// tile row.
|
||||
// The tile range end is described by the tile that starts at the bottom
|
||||
// left corner of the tile bounds, i.e. the first tile under the tile
|
||||
// bounds.
|
||||
class TileRange {
|
||||
public:
|
||||
// aTileBounds, aStart and aEnd need to be aligned with the tile grid.
|
||||
TileRange(const pixman_box32_t& aTileBounds,
|
||||
const IntPoint& aStart, const IntPoint& aEnd)
|
||||
: mTileBounds(aTileBounds)
|
||||
, mStart(aStart)
|
||||
, mEnd(aEnd)
|
||||
{}
|
||||
// aTileBounds needs to be aligned with the tile grid.
|
||||
explicit TileRange(const pixman_box32_t& aTileBounds)
|
||||
: mTileBounds(aTileBounds)
|
||||
, mStart(mTileBounds.x1, mTileBounds.y1)
|
||||
, mEnd(mTileBounds.x1, mTileBounds.y2)
|
||||
{}
|
||||
|
||||
TileIterator Begin() const { return TileIterator(mTileBounds, mStart); }
|
||||
TileIterator End() const { return TileIterator(mTileBounds, mEnd); }
|
||||
|
||||
// The number of tiles in this tile range.
|
||||
size_t Length() const
|
||||
{
|
||||
if (mEnd.y == mStart.y) {
|
||||
return (mEnd.x - mStart.x) / kTileSize;
|
||||
}
|
||||
int64_t numberOfFullRows = (((int64_t)mEnd.y - (int64_t)mStart.y) / kTileSize) - 1;
|
||||
int64_t tilesInFirstRow = ((int64_t)mTileBounds.x2 - (int64_t)mStart.x) / kTileSize;
|
||||
int64_t tilesInLastRow = ((int64_t)mEnd.x - (int64_t)mTileBounds.x1) / kTileSize;
|
||||
int64_t tilesInFullRow = ((int64_t)mTileBounds.x2 - (int64_t)mTileBounds.x1) / kTileSize;
|
||||
int64_t total = tilesInFirstRow + (tilesInFullRow * numberOfFullRows) + tilesInLastRow;
|
||||
MOZ_ASSERT(total > 0);
|
||||
// The total may be larger than what fits in a size_t, so clamp it to
|
||||
// SIZE_MAX in that case.
|
||||
return ((uint64_t)total > (uint64_t)SIZE_MAX) ? SIZE_MAX : (size_t)total;
|
||||
}
|
||||
|
||||
// If aTileOrigin does not describe a tile inside our tile bounds, move it
|
||||
// to the next tile that you'd encounter by "advancing" a tile iterator
|
||||
// inside these tile bounds. If aTileOrigin is after the last tile inside
|
||||
// our tile bounds, move it to the range end tile.
|
||||
// The result of this method is a valid end tile for a tile range with our
|
||||
// tile bounds.
|
||||
IntPoint MoveIntoBounds(const IntPoint& aTileOrigin) const
|
||||
{
|
||||
IntPoint p = aTileOrigin;
|
||||
if (p.x < mTileBounds.x1) {
|
||||
p.x = mTileBounds.x1;
|
||||
} else if (p.x >= mTileBounds.x2) {
|
||||
p.x = mTileBounds.x1;
|
||||
p.y += kTileSize;
|
||||
}
|
||||
if (p.y < mTileBounds.y1) {
|
||||
p.y = mTileBounds.y1;
|
||||
p.x = mTileBounds.x1;
|
||||
} else if (p.y >= mTileBounds.y2) {
|
||||
// There's only one valid state after the end of the tile range, and that's
|
||||
// the bottom left point of the tile bounds.
|
||||
p.x = mTileBounds.x1;
|
||||
p.y = mTileBounds.y2;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
private:
|
||||
const pixman_box32_t& mTileBounds;
|
||||
const IntPoint mStart;
|
||||
const IntPoint mEnd;
|
||||
};
|
||||
|
||||
static IntPoint
|
||||
TileContainingPoint(const IntPoint& aPoint)
|
||||
{
|
||||
return IntPoint(RoundDownToMultiple(aPoint.x, kTileSize),
|
||||
RoundDownToMultiple(aPoint.y, kTileSize));
|
||||
}
|
||||
|
||||
enum class IterationAction : uint8_t {
|
||||
CONTINUE,
|
||||
STOP
|
||||
};
|
||||
|
||||
enum class IterationEndReason : uint8_t {
|
||||
NOT_STOPPED,
|
||||
STOPPED
|
||||
};
|
||||
|
||||
template<
|
||||
typename HandleEmptyTilesFunction,
|
||||
typename HandleNonEmptyTileFunction,
|
||||
typename RectArrayT>
|
||||
IterationEndReason ProcessIntersectedTiles(const pixman_box32_t& aRect,
|
||||
RectArrayT& aRectArray,
|
||||
HandleEmptyTilesFunction aHandleEmptyTiles,
|
||||
HandleNonEmptyTileFunction aHandleNonEmptyTile)
|
||||
{
|
||||
pixman_box32_t tileBounds = {
|
||||
RoundDownToMultiple(aRect.x1, kTileSize),
|
||||
RoundDownToMultiple(aRect.y1, kTileSize),
|
||||
RoundUpToMultiple(aRect.x2, kTileSize),
|
||||
RoundUpToMultiple(aRect.y2, kTileSize)
|
||||
};
|
||||
if (tileBounds.x2 < tileBounds.x1 || tileBounds.y2 < tileBounds.y1) {
|
||||
// RoundUpToMultiple probably overflowed. Bail out.
|
||||
return IterationEndReason::STOPPED;
|
||||
}
|
||||
|
||||
TileRange tileRange(tileBounds);
|
||||
TileIterator rangeEnd = tileRange.End();
|
||||
|
||||
// tileIterator points to the next tile in tileRange, or to rangeEnd if we're
|
||||
// done.
|
||||
TileIterator tileIterator = tileRange.Begin();
|
||||
|
||||
// We iterate over the rectangle array. Depending on the position of the
|
||||
// rectangle we encounter, we may need to advance tileIterator by zero, one,
|
||||
// or more tiles:
|
||||
// - Zero if the rectangle we encountered is outside the tiles that
|
||||
// intersect aRect.
|
||||
// - One if the rectangle is in the exact tile that we're interested in next
|
||||
// (i.e. the tile that tileIterator points at).
|
||||
// - More than one if the encountered rectangle is in a tile that's further
|
||||
// to the right or to the bottom than tileIterator. In that case there is
|
||||
// at least one empty tile between the last rectangle we encountered and
|
||||
// the current one.
|
||||
for (size_t i = 0; i < aRectArray.Length() && tileIterator != rangeEnd; i++) {
|
||||
MOZ_ASSERT(aRectArray[i].x1 < aRectArray[i].x2 && aRectArray[i].y1 < aRectArray[i].y2, "empty rect");
|
||||
IntPoint rectOrigin(aRectArray[i].x1, aRectArray[i].y1);
|
||||
if (tileIterator.IsBeforeTileContainingPoint(rectOrigin)) {
|
||||
IntPoint tileOrigin = TileContainingPoint(rectOrigin);
|
||||
IntPoint afterEmptyTiles = tileRange.MoveIntoBounds(tileOrigin);
|
||||
TileRange emptyTiles(tileBounds, *tileIterator, afterEmptyTiles);
|
||||
if (aHandleEmptyTiles(aRectArray, i, emptyTiles) == IterationAction::STOP) {
|
||||
return IterationEndReason::STOPPED;
|
||||
}
|
||||
tileIterator = afterEmptyTiles;
|
||||
if (tileIterator == rangeEnd) {
|
||||
return IterationEndReason::NOT_STOPPED;
|
||||
}
|
||||
}
|
||||
if (tileIterator.IsAtTileContainingPoint(rectOrigin)) {
|
||||
pixman_box32_t rectIntersection = tileIterator.IntersectionWith(aRect);
|
||||
if (aHandleNonEmptyTile(aRectArray, i, rectIntersection) == IterationAction::STOP) {
|
||||
return IterationEndReason::STOPPED;
|
||||
}
|
||||
++tileIterator;
|
||||
}
|
||||
}
|
||||
|
||||
if (tileIterator != rangeEnd) {
|
||||
// We've looked at all of our existing rectangles but haven't covered all
|
||||
// of the tiles that we're interested in yet. So we need to deal with the
|
||||
// remaining tiles now.
|
||||
size_t endIndex = aRectArray.Length();
|
||||
TileRange emptyTiles(tileBounds, *tileIterator, *rangeEnd);
|
||||
if (aHandleEmptyTiles(aRectArray, endIndex, emptyTiles) == IterationAction::STOP) {
|
||||
return IterationEndReason::STOPPED;
|
||||
}
|
||||
}
|
||||
return IterationEndReason::NOT_STOPPED;
|
||||
}
|
||||
|
||||
static pixman_box32_t
|
||||
UnionBoundsOfNonEmptyBoxes(const pixman_box32_t& aBox1,
|
||||
const pixman_box32_t& aBox2)
|
||||
{
|
||||
return { std::min(aBox1.x1, aBox2.x1),
|
||||
std::min(aBox1.y1, aBox2.y1),
|
||||
std::max(aBox1.x2, aBox2.x2),
|
||||
std::max(aBox1.y2, aBox2.y2) };
|
||||
}
|
||||
|
||||
// Returns true when adding the rectangle was successful, and false if
|
||||
// allocation failed.
|
||||
// When this returns false, our internal state might not be consistent and we
|
||||
// need to be cleared.
|
||||
bool
|
||||
TiledRegionImpl::AddRect(const pixman_box32_t& aRect)
|
||||
{
|
||||
// We are adding a rectangle that can span multiple tiles.
|
||||
// For each empty tile that aRect intersects, we need to add the intersection
|
||||
// of aRect with that tile to mRects, respecting the order of mRects.
|
||||
// For each tile that already has a rectangle, we need to enlarge that
|
||||
// existing rectangle to include the intersection of aRect with the tile.
|
||||
return ProcessIntersectedTiles(aRect, mRects,
|
||||
[&aRect](nsTArray<pixman_box32_t>& rects, size_t& rectIndex, TileRange emptyTiles) {
|
||||
CheckedInt<size_t> newLength(rects.Length());
|
||||
newLength += emptyTiles.Length();
|
||||
if (!newLength.isValid() || newLength.value() >= kMaxTiles ||
|
||||
!rects.InsertElementsAt(rectIndex, emptyTiles.Length(), fallible)) {
|
||||
return IterationAction::STOP;
|
||||
}
|
||||
for (TileIterator tileIt = emptyTiles.Begin();
|
||||
tileIt != emptyTiles.End();
|
||||
++tileIt, ++rectIndex) {
|
||||
rects[rectIndex] = tileIt.IntersectionWith(aRect);
|
||||
}
|
||||
return IterationAction::CONTINUE;
|
||||
},
|
||||
[](nsTArray<pixman_box32_t>& rects, size_t rectIndex, const pixman_box32_t& rectIntersectionWithTile) {
|
||||
rects[rectIndex] =
|
||||
UnionBoundsOfNonEmptyBoxes(rects[rectIndex], rectIntersectionWithTile);
|
||||
return IterationAction::CONTINUE;
|
||||
}) == IterationEndReason::NOT_STOPPED;
|
||||
}
|
||||
|
||||
static bool
|
||||
NonEmptyBoxesIntersect(const pixman_box32_t& aBox1, const pixman_box32_t& aBox2)
|
||||
{
|
||||
return aBox1.x1 < aBox2.x2 && aBox2.x1 < aBox1.x2 &&
|
||||
aBox1.y1 < aBox2.y2 && aBox2.y1 < aBox1.y2;
|
||||
}
|
||||
|
||||
bool
|
||||
TiledRegionImpl::Intersects(const pixman_box32_t& aRect) const
|
||||
{
|
||||
// aRect intersects this region if it intersects any of our rectangles.
|
||||
return ProcessIntersectedTiles(aRect, mRects,
|
||||
[](const nsTArray<pixman_box32_t>& rects, size_t& rectIndex, TileRange emptyTiles) {
|
||||
// Ignore empty tiles and keep on iterating.
|
||||
return IterationAction::CONTINUE;
|
||||
},
|
||||
[](const nsTArray<pixman_box32_t>& rects, size_t rectIndex, const pixman_box32_t& rectIntersectionWithTile) {
|
||||
if (NonEmptyBoxesIntersect(rects[rectIndex], rectIntersectionWithTile)) {
|
||||
// Found an intersecting rectangle, so aRect intersects this region.
|
||||
return IterationAction::STOP;
|
||||
}
|
||||
return IterationAction::CONTINUE;
|
||||
}) == IterationEndReason::STOPPED;
|
||||
}
|
||||
|
||||
static bool
|
||||
NonEmptyBoxContainsNonEmptyBox(const pixman_box32_t& aBox1, const pixman_box32_t& aBox2)
|
||||
{
|
||||
return aBox1.x1 <= aBox2.x1 && aBox2.x2 <= aBox1.x2 &&
|
||||
aBox1.y1 <= aBox2.y1 && aBox2.y2 <= aBox1.y2;
|
||||
}
|
||||
|
||||
bool
|
||||
TiledRegionImpl::Contains(const pixman_box32_t& aRect) const
|
||||
{
|
||||
// aRect is contained in this region if aRect does not intersect any empty
|
||||
// tiles and, for each non-empty tile, if the intersection of aRect with that
|
||||
// tile is contained in the existing rectangle we have in that tile.
|
||||
return ProcessIntersectedTiles(aRect, mRects,
|
||||
[](const nsTArray<pixman_box32_t>& rects, size_t& rectIndex, TileRange emptyTiles) {
|
||||
// Found an empty tile that intersects aRect, so aRect is not contained
|
||||
// in this region.
|
||||
return IterationAction::STOP;
|
||||
},
|
||||
[](const nsTArray<pixman_box32_t>& rects, size_t rectIndex, const pixman_box32_t& rectIntersectionWithTile) {
|
||||
if (!NonEmptyBoxContainsNonEmptyBox(rects[rectIndex], rectIntersectionWithTile)) {
|
||||
// Our existing rectangle in this tile does not cover the part of aRect that
|
||||
// intersects this tile, so aRect is not contained in this region.
|
||||
return IterationAction::STOP;
|
||||
}
|
||||
return IterationAction::CONTINUE;
|
||||
}) == IterationEndReason::NOT_STOPPED;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
208
gfx/src/TiledRegion.h
Normal file
208
gfx/src/TiledRegion.h
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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_GFX_TILEDREGION_H_
|
||||
#define MOZILLA_GFX_TILEDREGION_H_
|
||||
|
||||
#include "mozilla/ArrayView.h"
|
||||
#include "mozilla/gfx/Rect.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "nsRegion.h"
|
||||
#include "pixman.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
// See TiledRegion.cpp for documentation on TiledRegionImpl.
|
||||
class TiledRegionImpl {
|
||||
public:
|
||||
void Clear() { mRects.Clear(); }
|
||||
bool AddRect(const pixman_box32_t& aRect);
|
||||
bool Intersects(const pixman_box32_t& aRect) const;
|
||||
bool Contains(const pixman_box32_t& aRect) const;
|
||||
operator ArrayView<pixman_box32_t>() const { return ArrayView<pixman_box32_t>(mRects); }
|
||||
|
||||
private:
|
||||
nsTArray<pixman_box32_t> mRects;
|
||||
};
|
||||
|
||||
/**
|
||||
* A auto-simplifying region type that supports one rectangle per tile.
|
||||
* The virtual tile grid is anchored at (0, 0) and has quadratic tiles whose
|
||||
* size is hard-coded as kTileSize in TiledRegion.cpp.
|
||||
* A TiledRegion starts out empty. You can add rectangles or (regular) regions
|
||||
* into it by calling Add(). Add() is a mutating union operation (similar to
|
||||
* OrWith on nsRegion) that's *not* exact, because it will enlarge the region as
|
||||
* necessary to satisfy the "one rectangle per tile" requirement.
|
||||
* Tiled regions convert implicitly to the underlying regular region type.
|
||||
* The only way to remove parts from a TiledRegion is by calling SetEmpty().
|
||||
*/
|
||||
template<typename RegionT>
|
||||
class TiledRegion {
|
||||
public:
|
||||
typedef typename RegionT::RectType RectT;
|
||||
|
||||
TiledRegion()
|
||||
: mCoversBounds(false)
|
||||
{}
|
||||
|
||||
TiledRegion(const TiledRegion& aOther)
|
||||
: mBounds(aOther.mBounds)
|
||||
, mImpl(aOther.mImpl)
|
||||
, mCoversBounds(false)
|
||||
{}
|
||||
|
||||
TiledRegion(TiledRegion&& aOther)
|
||||
: mBounds(aOther.mBounds)
|
||||
, mImpl(Move(aOther.mImpl))
|
||||
, mCoversBounds(false)
|
||||
{}
|
||||
|
||||
RegionT GetRegion() const
|
||||
{
|
||||
if (mBounds.IsEmpty()) {
|
||||
return RegionT();
|
||||
}
|
||||
if (mCoversBounds) {
|
||||
// Rect limit hit or allocation failed, treat as 1 rect.
|
||||
return RegionT(mBounds);
|
||||
}
|
||||
return RegionT(mImpl);
|
||||
}
|
||||
|
||||
TiledRegion& operator=(const TiledRegion& aOther)
|
||||
{
|
||||
if (&aOther != this) {
|
||||
mBounds = aOther.mBounds;
|
||||
mImpl = aOther.mImpl;
|
||||
mCoversBounds = aOther.mCoversBounds;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Add(const RectT& aRect)
|
||||
{
|
||||
if (aRect.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Maybe<RectT> newBounds = mBounds.SafeUnion(aRect);
|
||||
if (!newBounds) {
|
||||
return;
|
||||
}
|
||||
mBounds = newBounds.value();
|
||||
MOZ_ASSERT(!mBounds.Overflows());
|
||||
|
||||
if (mCoversBounds) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mImpl.AddRect(RectToBox(aRect))) {
|
||||
FallBackToBounds();
|
||||
}
|
||||
}
|
||||
|
||||
void Add(const RegionT& aRegion)
|
||||
{
|
||||
Maybe<RectT> newBounds = mBounds.SafeUnion(aRegion.GetBounds());
|
||||
if (!newBounds) {
|
||||
return;
|
||||
}
|
||||
mBounds = newBounds.value();
|
||||
MOZ_ASSERT(!mBounds.Overflows());
|
||||
|
||||
if (mCoversBounds) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
|
||||
RectT r = iter.Get();
|
||||
if (r.IsEmpty() || r.Overflows()) {
|
||||
// This can happen if e.g. a negative-width rect was wrapped into a
|
||||
// region. Treat it the same as we would if such a rect was passed to
|
||||
// the Add(const RectT&) function.
|
||||
continue;
|
||||
}
|
||||
if (!mImpl.AddRect(RectToBox(r))) {
|
||||
FallBackToBounds();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IsEmpty() const { return mBounds.IsEmpty(); }
|
||||
|
||||
void SetEmpty()
|
||||
{
|
||||
mBounds.SetEmpty();
|
||||
mImpl.Clear();
|
||||
mCoversBounds = false;
|
||||
}
|
||||
|
||||
RectT GetBounds() const { return mBounds; }
|
||||
bool CoversBounds() const { return mCoversBounds; }
|
||||
|
||||
bool Intersects(const RectT& aRect) const
|
||||
{
|
||||
if (aRect.IsEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if (aRect.Overflows() || !mBounds.Intersects(aRect)) {
|
||||
return false;
|
||||
}
|
||||
if (mCoversBounds) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return mImpl.Intersects(RectToBox(aRect));
|
||||
}
|
||||
|
||||
bool Contains(const RectT& aRect) const
|
||||
{
|
||||
if (aRect.IsEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if (aRect.Overflows() || !mBounds.Contains(aRect)) {
|
||||
return false;
|
||||
}
|
||||
if (mCoversBounds) {
|
||||
return true;
|
||||
}
|
||||
return mImpl.Contains(RectToBox(aRect));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void FallBackToBounds()
|
||||
{
|
||||
mCoversBounds = true;
|
||||
mImpl.Clear();
|
||||
}
|
||||
|
||||
static pixman_box32_t RectToBox(const RectT& aRect)
|
||||
{
|
||||
MOZ_ASSERT(!aRect.IsEmpty());
|
||||
MOZ_ASSERT(!aRect.Overflows());
|
||||
return { aRect.x, aRect.y, aRect.XMost(), aRect.YMost() };
|
||||
}
|
||||
|
||||
RectT mBounds;
|
||||
TiledRegionImpl mImpl;
|
||||
|
||||
// mCoversBounds is true if we bailed out due to a large number of tiles.
|
||||
// mCoversBounds being true means that this TiledRegion is just a simple
|
||||
// rectangle (our mBounds).
|
||||
// Once set to true, the TiledRegion will stay in this state until SetEmpty
|
||||
// is called.
|
||||
bool mCoversBounds;
|
||||
};
|
||||
|
||||
typedef TiledRegion<IntRegion> TiledIntRegion;
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* MOZILLA_GFX_TILEDREGION_H_ */
|
||||
23
gfx/src/X11UndefineNone.h
Normal file
23
gfx/src/X11UndefineNone.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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/. */
|
||||
|
||||
// The header <X11/X.h> defines "None" as a macro that expands to "0L".
|
||||
// This is terrible because many enumerations have an enumerator named "None".
|
||||
// To work around this, we undefine the macro "None", and define a replacement
|
||||
// macro named "X11None".
|
||||
// Include this header after including X11 headers, where necessary.
|
||||
#ifdef None
|
||||
# undef None
|
||||
# define X11None 0L
|
||||
// <X11/X.h> also defines "RevertToNone" as a macro that expands to "(int)None".
|
||||
// Since we are undefining "None", that stops working. To keep it working,
|
||||
// we undefine "RevertToNone" and redefine it in terms of "X11None".
|
||||
# ifdef RevertToNone
|
||||
# undef RevertToNone
|
||||
# define RevertToNone (int)X11None
|
||||
# endif
|
||||
#endif
|
||||
|
||||
94
gfx/src/X11Util.cpp
Normal file
94
gfx/src/X11Util.cpp
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=8 et :
|
||||
*/
|
||||
/* 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 "X11Util.h"
|
||||
#include "nsDebug.h" // for NS_ASSERTION, etc
|
||||
#include "MainThreadUtils.h" // for NS_IsMainThread
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
void
|
||||
FindVisualAndDepth(Display* aDisplay, VisualID aVisualID,
|
||||
Visual** aVisual, int* aDepth)
|
||||
{
|
||||
const Screen* screen = DefaultScreenOfDisplay(aDisplay);
|
||||
|
||||
for (int d = 0; d < screen->ndepths; d++) {
|
||||
Depth *d_info = &screen->depths[d];
|
||||
for (int v = 0; v < d_info->nvisuals; v++) {
|
||||
Visual* visual = &d_info->visuals[v];
|
||||
if (visual->visualid == aVisualID) {
|
||||
*aVisual = visual;
|
||||
*aDepth = d_info->depth;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_ASSERTION(aVisualID == X11None, "VisualID not on Screen.");
|
||||
*aVisual = nullptr;
|
||||
*aDepth = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
FinishX(Display* aDisplay)
|
||||
{
|
||||
unsigned long lastRequest = NextRequest(aDisplay) - 1;
|
||||
if (lastRequest == LastKnownRequestProcessed(aDisplay))
|
||||
return;
|
||||
|
||||
XSync(aDisplay, False);
|
||||
}
|
||||
|
||||
ScopedXErrorHandler::ErrorEvent* ScopedXErrorHandler::sXErrorPtr;
|
||||
|
||||
int
|
||||
ScopedXErrorHandler::ErrorHandler(Display *, XErrorEvent *ev)
|
||||
{
|
||||
// only record the error if no error was previously recorded.
|
||||
// this means that in case of multiple errors, it's the first error that we report.
|
||||
if (!sXErrorPtr->mError.error_code)
|
||||
sXErrorPtr->mError = *ev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ScopedXErrorHandler::ScopedXErrorHandler(bool aAllowOffMainThread)
|
||||
{
|
||||
if (!aAllowOffMainThread) {
|
||||
// Off main thread usage is not safe in general, but OMTC GL layers uses this
|
||||
// with the main thread blocked, which makes it safe.
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_IsMainThread(),
|
||||
"ScopedXErrorHandler being called off main thread, may cause issues");
|
||||
}
|
||||
// let sXErrorPtr point to this object's mXError object, but don't reset this mXError object!
|
||||
// think of the case of nested ScopedXErrorHandler's.
|
||||
mOldXErrorPtr = sXErrorPtr;
|
||||
sXErrorPtr = &mXError;
|
||||
mOldErrorHandler = XSetErrorHandler(ErrorHandler);
|
||||
}
|
||||
|
||||
ScopedXErrorHandler::~ScopedXErrorHandler()
|
||||
{
|
||||
sXErrorPtr = mOldXErrorPtr;
|
||||
XSetErrorHandler(mOldErrorHandler);
|
||||
}
|
||||
|
||||
bool
|
||||
ScopedXErrorHandler::SyncAndGetError(Display *dpy, XErrorEvent *ev)
|
||||
{
|
||||
FinishX(dpy);
|
||||
|
||||
bool retval = mXError.mError.error_code != 0;
|
||||
if (ev)
|
||||
*ev = mXError.mError;
|
||||
mXError = ErrorEvent(); // reset
|
||||
return retval;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
148
gfx/src/X11Util.h
Normal file
148
gfx/src/X11Util.h
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=8 et :
|
||||
*/
|
||||
/* 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_X11Util_h
|
||||
#define mozilla_X11Util_h
|
||||
|
||||
// Utilities common to all X clients, regardless of UI toolkit.
|
||||
|
||||
#if defined(MOZ_WIDGET_GTK)
|
||||
# include <gdk/gdk.h>
|
||||
# include <gdk/gdkx.h>
|
||||
# include "X11UndefineNone.h"
|
||||
#else
|
||||
# error Unknown toolkit
|
||||
#endif
|
||||
|
||||
#include <string.h> // for memset
|
||||
#include "mozilla/Scoped.h" // for SCOPED_TEMPLATE
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* Return the default X Display created and used by the UI toolkit.
|
||||
*/
|
||||
inline Display*
|
||||
DefaultXDisplay()
|
||||
{
|
||||
#if defined(MOZ_WIDGET_GTK)
|
||||
return GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets *aVisual to point to aDisplay's Visual struct corresponding to
|
||||
* aVisualID, and *aDepth to its depth. When aVisualID is None, these are set
|
||||
* to nullptr and 0 respectively. Both out-parameter pointers are assumed
|
||||
* non-nullptr.
|
||||
*/
|
||||
void
|
||||
FindVisualAndDepth(Display* aDisplay, VisualID aVisualID,
|
||||
Visual** aVisual, int* aDepth);
|
||||
|
||||
|
||||
/**
|
||||
* Ensure that all X requests have been processed.
|
||||
*
|
||||
* This is similar to XSync, but doesn't need a round trip if the previous
|
||||
* request was synchronous or if events have been received since the last
|
||||
* request. Subsequent FinishX calls will be noops if there have been no
|
||||
* intermediate requests.
|
||||
*/
|
||||
|
||||
void
|
||||
FinishX(Display* aDisplay);
|
||||
|
||||
/**
|
||||
* Invoke XFree() on a pointer to memory allocated by Xlib (if the
|
||||
* pointer is nonnull) when this class goes out of scope.
|
||||
*/
|
||||
template <typename T>
|
||||
struct ScopedXFreePtrTraits
|
||||
{
|
||||
typedef T *type;
|
||||
static T *empty() { return nullptr; }
|
||||
static void release(T *ptr) { if (ptr != nullptr) XFree(ptr); }
|
||||
};
|
||||
SCOPED_TEMPLATE(ScopedXFree, ScopedXFreePtrTraits)
|
||||
|
||||
/**
|
||||
* On construction, set a graceful X error handler that doesn't crash the application and records X errors.
|
||||
* On destruction, restore the X error handler to what it was before construction.
|
||||
*
|
||||
* The SyncAndGetError() method allows to know whether a X error occurred, optionally allows to get the full XErrorEvent,
|
||||
* and resets the recorded X error state so that a single X error will be reported only once.
|
||||
*
|
||||
* Nesting is correctly handled: multiple nested ScopedXErrorHandler's don't interfere with each other's state. However,
|
||||
* if SyncAndGetError is not called on the nested ScopedXErrorHandler, then any X errors caused by X calls made while the nested
|
||||
* ScopedXErrorHandler was in place may then be caught by the other ScopedXErrorHandler. This is just a result of X being
|
||||
* asynchronous and us not doing any implicit syncing: the only method in this class what causes syncing is SyncAndGetError().
|
||||
*
|
||||
* This class is not thread-safe at all. It is assumed that only one thread is using any ScopedXErrorHandler's. Given that it's
|
||||
* not used on Mac, it should be easy to make it thread-safe by using thread-local storage with __thread.
|
||||
*/
|
||||
class ScopedXErrorHandler
|
||||
{
|
||||
public:
|
||||
// trivial wrapper around XErrorEvent, just adding ctor initializing by zero.
|
||||
struct ErrorEvent
|
||||
{
|
||||
XErrorEvent mError;
|
||||
|
||||
ErrorEvent()
|
||||
{
|
||||
memset(this, 0, sizeof(ErrorEvent));
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
// this ScopedXErrorHandler's ErrorEvent object
|
||||
ErrorEvent mXError;
|
||||
|
||||
// static pointer for use by the error handler
|
||||
static ErrorEvent* sXErrorPtr;
|
||||
|
||||
// what to restore sXErrorPtr to on destruction
|
||||
ErrorEvent* mOldXErrorPtr;
|
||||
|
||||
// what to restore the error handler to on destruction
|
||||
int (*mOldErrorHandler)(Display *, XErrorEvent *);
|
||||
|
||||
public:
|
||||
|
||||
static int
|
||||
ErrorHandler(Display *, XErrorEvent *ev);
|
||||
|
||||
/**
|
||||
* @param aAllowOffMainThread whether to warn if used off main thread
|
||||
*/
|
||||
explicit ScopedXErrorHandler(bool aAllowOffMainThread = false);
|
||||
|
||||
~ScopedXErrorHandler();
|
||||
|
||||
/** \returns true if a X error occurred since the last time this method was called on this ScopedXErrorHandler object,
|
||||
* or since the creation of this ScopedXErrorHandler object if this method was never called on it.
|
||||
*
|
||||
* \param ev this optional parameter, if set, will be filled with the XErrorEvent object. If multiple errors occurred,
|
||||
* the first one will be returned.
|
||||
*/
|
||||
bool SyncAndGetError(Display *dpy, XErrorEvent *ev = nullptr);
|
||||
};
|
||||
|
||||
class OffMainThreadScopedXErrorHandler : public ScopedXErrorHandler
|
||||
{
|
||||
public:
|
||||
OffMainThreadScopedXErrorHandler()
|
||||
: ScopedXErrorHandler(true)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_X11Util_h
|
||||
145
gfx/src/gfxCrashReporterUtils.cpp
Normal file
145
gfx/src/gfxCrashReporterUtils.cpp
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
/* -*- 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 "gfxCrashReporterUtils.h"
|
||||
|
||||
#if defined(MOZ_CRASHREPORTER)
|
||||
#define MOZ_GFXFEATUREREPORTER 1
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_GFXFEATUREREPORTER
|
||||
#include "gfxCrashReporterUtils.h"
|
||||
#include <string.h> // for strcmp
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
|
||||
#include "mozilla/Services.h" // for GetObserverService
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "mozilla/mozalloc.h" // for operator new, etc
|
||||
#include "mozilla/RefPtr.h" // for RefPtr
|
||||
#include "nsCOMPtr.h" // for nsCOMPtr
|
||||
#include "nsError.h" // for NS_OK, NS_FAILED, nsresult
|
||||
#include "nsExceptionHandler.h" // for AppendAppNotesToCrashReport
|
||||
#include "nsID.h"
|
||||
#include "nsIEventTarget.h" // for NS_DISPATCH_NORMAL
|
||||
#include "nsIObserver.h" // for nsIObserver, etc
|
||||
#include "nsIObserverService.h" // for nsIObserverService
|
||||
#include "nsIRunnable.h" // for nsIRunnable
|
||||
#include "nsISupports.h"
|
||||
#include "nsTArray.h" // for nsTArray
|
||||
#include "nsThreadUtils.h" // for NS_DispatchToMainThread, etc
|
||||
#include "nscore.h" // for NS_IMETHOD, NS_IMETHODIMP, etc
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static nsTArray<nsCString> *gFeaturesAlreadyReported = nullptr;
|
||||
static StaticMutex gFeaturesAlreadyReportedMutex;
|
||||
|
||||
class ObserverToDestroyFeaturesAlreadyReported final : public nsIObserver
|
||||
{
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
ObserverToDestroyFeaturesAlreadyReported() {}
|
||||
private:
|
||||
virtual ~ObserverToDestroyFeaturesAlreadyReported() {}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(ObserverToDestroyFeaturesAlreadyReported,
|
||||
nsIObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
ObserverToDestroyFeaturesAlreadyReported::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
if (!strcmp(aTopic, "xpcom-shutdown")) {
|
||||
StaticMutexAutoLock al(gFeaturesAlreadyReportedMutex);
|
||||
if (gFeaturesAlreadyReported) {
|
||||
delete gFeaturesAlreadyReported;
|
||||
gFeaturesAlreadyReported = nullptr;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class RegisterObserverRunnable : public Runnable {
|
||||
public:
|
||||
NS_IMETHOD Run() override {
|
||||
// LeakLog made me do this. Basically, I just wanted gFeaturesAlreadyReported to be a static nsTArray<nsCString>,
|
||||
// and LeakLog was complaining about leaks like this:
|
||||
// leaked 1 instance of nsTArray_base with size 8 bytes
|
||||
// leaked 7 instances of nsStringBuffer with size 8 bytes each (56 bytes total)
|
||||
// So this is a work-around using a pointer, and using a nsIObserver to deallocate on xpcom shutdown.
|
||||
// Yay for fighting bloat.
|
||||
nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
|
||||
if (!observerService)
|
||||
return NS_OK;
|
||||
RefPtr<ObserverToDestroyFeaturesAlreadyReported> observer = new ObserverToDestroyFeaturesAlreadyReported;
|
||||
observerService->AddObserver(observer, "xpcom-shutdown", false);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
class AppendAppNotesRunnable : public CancelableRunnable {
|
||||
public:
|
||||
explicit AppendAppNotesRunnable(const nsACString& aFeatureStr)
|
||||
: mFeatureString(aFeatureStr)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override {
|
||||
CrashReporter::AppendAppNotesToCrashReport(mFeatureString);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsAutoCString mFeatureString;
|
||||
};
|
||||
|
||||
void
|
||||
ScopedGfxFeatureReporter::WriteAppNote(char statusChar)
|
||||
{
|
||||
StaticMutexAutoLock al(gFeaturesAlreadyReportedMutex);
|
||||
|
||||
if (!gFeaturesAlreadyReported) {
|
||||
gFeaturesAlreadyReported = new nsTArray<nsCString>;
|
||||
nsCOMPtr<nsIRunnable> r = new RegisterObserverRunnable();
|
||||
NS_DispatchToMainThread(r);
|
||||
}
|
||||
|
||||
nsAutoCString featureString;
|
||||
featureString.AppendPrintf("%s%c ",
|
||||
mFeature,
|
||||
statusChar);
|
||||
|
||||
if (!gFeaturesAlreadyReported->Contains(featureString)) {
|
||||
gFeaturesAlreadyReported->AppendElement(featureString);
|
||||
AppNote(featureString);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ScopedGfxFeatureReporter::AppNote(const nsACString& aMessage)
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
CrashReporter::AppendAppNotesToCrashReport(aMessage);
|
||||
} else {
|
||||
nsCOMPtr<nsIRunnable> r = new AppendAppNotesRunnable(aMessage);
|
||||
NS_DispatchToMainThread(r);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace mozilla
|
||||
|
||||
#else
|
||||
|
||||
namespace mozilla {
|
||||
void ScopedGfxFeatureReporter::WriteAppNote(char) {}
|
||||
void ScopedGfxFeatureReporter::AppNote(const nsACString&) {}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
51
gfx/src/gfxCrashReporterUtils.h
Normal file
51
gfx/src/gfxCrashReporterUtils.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/* -*- 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 gfxCrashReporterUtils_h__
|
||||
#define gfxCrashReporterUtils_h__
|
||||
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/** \class ScopedGfxFeatureReporter
|
||||
*
|
||||
* On creation, adds "FeatureName?" to AppNotes
|
||||
* On destruction, adds "FeatureName-", or "FeatureName+" if you called SetSuccessful().
|
||||
*
|
||||
* Any such string is added at most once to AppNotes, and is subsequently skipped.
|
||||
*
|
||||
* This ScopedGfxFeatureReporter class is designed to be fool-proof to use in functions that
|
||||
* have many exit points. We don't want to encourage having function with many exit points.
|
||||
* It just happens that our graphics features initialization functions are like that.
|
||||
*/
|
||||
class ScopedGfxFeatureReporter
|
||||
{
|
||||
public:
|
||||
explicit ScopedGfxFeatureReporter(const char *aFeature, bool aForce = false)
|
||||
: mFeature(aFeature), mStatusChar('-')
|
||||
{
|
||||
WriteAppNote(aForce ? '!' : '?');
|
||||
}
|
||||
~ScopedGfxFeatureReporter() {
|
||||
WriteAppNote(mStatusChar);
|
||||
}
|
||||
void SetSuccessful() { mStatusChar = '+'; }
|
||||
|
||||
static void AppNote(const nsACString& aMessage);
|
||||
|
||||
class AppNoteWritingRunnable;
|
||||
|
||||
protected:
|
||||
const char *mFeature;
|
||||
char mStatusChar;
|
||||
|
||||
private:
|
||||
void WriteAppNote(char statusChar);
|
||||
};
|
||||
|
||||
} // end namespace mozilla
|
||||
|
||||
#endif // gfxCrashReporterUtils_h__
|
||||
59
gfx/src/gfxTelemetry.cpp
Normal file
59
gfx/src/gfxTelemetry.cpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/* -*- Mode: IDL; 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 "gfxTelemetry.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
const char*
|
||||
FeatureStatusToString(FeatureStatus aStatus)
|
||||
{
|
||||
switch (aStatus) {
|
||||
case FeatureStatus::Unused:
|
||||
return "unused";
|
||||
case FeatureStatus::Unavailable:
|
||||
return "unavailable";
|
||||
case FeatureStatus::CrashedInHandler:
|
||||
return "crashed";
|
||||
case FeatureStatus::Blocked:
|
||||
return "blocked";
|
||||
case FeatureStatus::Blacklisted:
|
||||
return "blacklisted";
|
||||
case FeatureStatus::Failed:
|
||||
return "failed";
|
||||
case FeatureStatus::Disabled:
|
||||
return "disabled";
|
||||
case FeatureStatus::Available:
|
||||
return "available";
|
||||
case FeatureStatus::ForceEnabled:
|
||||
return "force_enabled";
|
||||
case FeatureStatus::CrashedOnStartup:
|
||||
return "crashed_on_startup";
|
||||
case FeatureStatus::Broken:
|
||||
return "broken";
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("missing status case");
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
IsFeatureStatusFailure(FeatureStatus aStatus)
|
||||
{
|
||||
return !(aStatus == FeatureStatus::Unused ||
|
||||
aStatus == FeatureStatus::Available ||
|
||||
aStatus == FeatureStatus::ForceEnabled);
|
||||
}
|
||||
|
||||
bool
|
||||
IsFeatureStatusSuccess(FeatureStatus aStatus)
|
||||
{
|
||||
return aStatus == FeatureStatus::Available ||
|
||||
aStatus == FeatureStatus::ForceEnabled;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
70
gfx/src/gfxTelemetry.h
Normal file
70
gfx/src/gfxTelemetry.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/* -*- Mode: IDL; 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 gfx_src_gfxTelemetry_h__
|
||||
#define gfx_src_gfxTelemetry_h__
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
// Describes the status of a graphics feature, in terms of whether or not we've
|
||||
// attempted to initialize the feature, and if so, whether or not it succeeded
|
||||
// (and if not, why).
|
||||
enum class FeatureStatus
|
||||
{
|
||||
// This feature has not been requested.
|
||||
Unused,
|
||||
|
||||
// This feature is unavailable due to Safe Mode, not being included with
|
||||
// the operating system, or a dependent feature being disabled.
|
||||
Unavailable,
|
||||
|
||||
// This feature crashed immediately when we tried to initialize it, but we
|
||||
// were able to recover via SEH (or something similar).
|
||||
CrashedInHandler,
|
||||
|
||||
// This feature was blocked for reasons outside the blacklist, such as a
|
||||
// runtime test failing.
|
||||
Blocked,
|
||||
|
||||
// This feature has been blocked by the graphics blacklist.
|
||||
Blacklisted,
|
||||
|
||||
// This feature was attempted but failed to activate.
|
||||
Failed,
|
||||
|
||||
// This feature was explicitly disabled by the user.
|
||||
Disabled,
|
||||
|
||||
// This feature is available for use.
|
||||
Available,
|
||||
|
||||
// This feature was explicitly force-enabled by the user.
|
||||
ForceEnabled,
|
||||
|
||||
// This feature was disabled due to the startup crash guard.
|
||||
CrashedOnStartup,
|
||||
|
||||
// This feature was attempted but later determined to be broken.
|
||||
Broken,
|
||||
|
||||
// Add new entries above here.
|
||||
LAST
|
||||
};
|
||||
|
||||
const char* FeatureStatusToString(FeatureStatus aStatus);
|
||||
bool IsFeatureStatusFailure(FeatureStatus aStatus);
|
||||
bool IsFeatureStatusSuccess(FeatureStatus aStatus);
|
||||
|
||||
enum class TelemetryDeviceCode : uint32_t {
|
||||
Content = 0,
|
||||
Image = 1,
|
||||
D2D1 = 2
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // gfx_src_gfxTelemetry_h__
|
||||
94
gfx/src/moz.build
Normal file
94
gfx/src/moz.build
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
# -*- 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/.
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIFontEnumerator.idl',
|
||||
'nsIScriptableRegion.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'gfx'
|
||||
|
||||
DEFINES['MOZ_APP_VERSION'] = '"%s"' % CONFIG['MOZ_APP_VERSION']
|
||||
|
||||
EXPORTS += [
|
||||
'DriverCrashGuard.h',
|
||||
'FilterSupport.h',
|
||||
'gfxCrashReporterUtils.h',
|
||||
'gfxTelemetry.h',
|
||||
'nsBoundingMetrics.h',
|
||||
'nsColor.h',
|
||||
'nsColorNameList.h',
|
||||
'nsColorNames.h',
|
||||
'nsCoord.h',
|
||||
'nsDeviceContext.h',
|
||||
'nsFont.h',
|
||||
'nsFontMetrics.h',
|
||||
'nsGfxCIID.h',
|
||||
'nsITheme.h',
|
||||
'nsMargin.h',
|
||||
'nsPoint.h',
|
||||
'nsRect.h',
|
||||
'nsRegion.h',
|
||||
'nsRegionFwd.h',
|
||||
'nsRenderingContext.h',
|
||||
'nsSize.h',
|
||||
'nsThemeConstants.h',
|
||||
'nsTransform2D.h',
|
||||
'PingPongRegion.h',
|
||||
'RegionBuilder.h',
|
||||
'X11UndefineNone.h'
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'AppUnits.h',
|
||||
'ArrayView.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.gfx += [
|
||||
'TiledRegion.h',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_X11']:
|
||||
EXPORTS.mozilla += ['X11Util.h']
|
||||
SOURCES += [
|
||||
'X11Util.cpp',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'DriverCrashGuard.cpp',
|
||||
'FilterSupport.cpp',
|
||||
'gfxCrashReporterUtils.cpp',
|
||||
'gfxTelemetry.cpp',
|
||||
'nsColor.cpp',
|
||||
'nsFont.cpp',
|
||||
'nsFontMetrics.cpp',
|
||||
'nsRect.cpp',
|
||||
'nsRegion.cpp',
|
||||
'nsScriptableRegion.cpp',
|
||||
'nsThebesFontEnumerator.cpp',
|
||||
'nsThebesGfxFactory.cpp',
|
||||
'nsTransform2D.cpp',
|
||||
'TiledRegion.cpp',
|
||||
]
|
||||
|
||||
# nsDeviceContext.cpp cannot be built in unified mode because it pulls in OS X system headers.
|
||||
SOURCES += [
|
||||
'nsDeviceContext.cpp',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/ipc', # for ContentChild.h
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
|
||||
CXXFLAGS += CONFIG['TK_CFLAGS']
|
||||
|
||||
if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
|
||||
CXXFLAGS += CONFIG['MOZ_PANGO_CFLAGS']
|
||||
87
gfx/src/nsBoundingMetrics.h
Normal file
87
gfx/src/nsBoundingMetrics.h
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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 __nsBoundingMetrics_h
|
||||
#define __nsBoundingMetrics_h
|
||||
|
||||
#include "nsCoord.h"
|
||||
#include <algorithm>
|
||||
|
||||
/* Struct used for accurate measurements of a string, in order to
|
||||
* allow precise positioning when processing MathML. This is in its
|
||||
* own header file because some very-widely-included headers need it
|
||||
* but not the rest of nsFontMetrics, or vice versa.
|
||||
*/
|
||||
|
||||
struct nsBoundingMetrics {
|
||||
|
||||
///////////
|
||||
// Metrics that _exactly_ enclose the text:
|
||||
|
||||
// The character coordinate system is the one used on X Windows:
|
||||
// 1. The origin is located at the intersection of the baseline
|
||||
// with the left of the character's cell.
|
||||
// 2. All horizontal bearings are oriented from left to right.
|
||||
// 2. All horizontal bearings are oriented from left to right.
|
||||
// 3. The ascent is oriented from bottom to top (being 0 at the orgin).
|
||||
// 4. The descent is oriented from top to bottom (being 0 at the origin).
|
||||
|
||||
// Note that Win32/Mac/PostScript use a different convention for
|
||||
// the descent (all vertical measurements are oriented from bottom
|
||||
// to top on these palatforms). Make sure to flip the sign of the
|
||||
// descent on these platforms for cross-platform compatibility.
|
||||
|
||||
// Any of the following member variables listed here can have
|
||||
// positive or negative value.
|
||||
|
||||
nscoord leftBearing;
|
||||
/* The horizontal distance from the origin of the drawing
|
||||
operation to the left-most part of the drawn string. */
|
||||
|
||||
nscoord rightBearing;
|
||||
/* The horizontal distance from the origin of the drawing
|
||||
operation to the right-most part of the drawn string.
|
||||
The _exact_ width of the string is therefore:
|
||||
rightBearing - leftBearing */
|
||||
|
||||
nscoord ascent;
|
||||
/* The vertical distance from the origin of the drawing
|
||||
operation to the top-most part of the drawn string. */
|
||||
|
||||
nscoord descent;
|
||||
/* The vertical distance from the origin of the drawing
|
||||
operation to the bottom-most part of the drawn string.
|
||||
The _exact_ height of the string is therefore:
|
||||
ascent + descent */
|
||||
|
||||
nscoord width;
|
||||
/* The horizontal distance from the origin of the drawing
|
||||
operation to the correct origin for drawing another string
|
||||
to follow the current one. Depending on the font, this
|
||||
could be greater than or less than the right bearing. */
|
||||
|
||||
nsBoundingMetrics() : leftBearing(0), rightBearing(0),
|
||||
ascent(0), descent(0), width(0)
|
||||
{}
|
||||
|
||||
void
|
||||
operator += (const nsBoundingMetrics& bm) {
|
||||
if (ascent + descent == 0 && rightBearing - leftBearing == 0) {
|
||||
ascent = bm.ascent;
|
||||
descent = bm.descent;
|
||||
leftBearing = width + bm.leftBearing;
|
||||
rightBearing = width + bm.rightBearing;
|
||||
}
|
||||
else {
|
||||
if (ascent < bm.ascent) ascent = bm.ascent;
|
||||
if (descent < bm.descent) descent = bm.descent;
|
||||
leftBearing = std::min(leftBearing, width + bm.leftBearing);
|
||||
rightBearing = std::max(rightBearing, width + bm.rightBearing);
|
||||
}
|
||||
width += bm.width;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __nsBoundingMetrics_h
|
||||
361
gfx/src/nsColor.cpp
Normal file
361
gfx/src/nsColor.cpp
Normal file
|
|
@ -0,0 +1,361 @@
|
|||
/* -*- 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" // for ArrayLength
|
||||
#include "mozilla/mozalloc.h" // for operator delete, etc
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
|
||||
#include "nsColor.h"
|
||||
#include <sys/types.h> // for int32_t
|
||||
#include "nsColorNames.h" // for nsColorNames
|
||||
#include "nsDebug.h" // for NS_ASSERTION, etc
|
||||
#include "nsStaticNameTable.h"
|
||||
#include "nsString.h" // for nsAutoCString, nsString, etc
|
||||
#include "nscore.h" // for nsAString, etc
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
// define an array of all color names
|
||||
#define GFX_COLOR(_name, _value) #_name,
|
||||
static const char* const kColorNames[] = {
|
||||
#include "nsColorNameList.h"
|
||||
};
|
||||
#undef GFX_COLOR
|
||||
|
||||
// define an array of all color name values
|
||||
#define GFX_COLOR(_name, _value) _value,
|
||||
static const nscolor kColors[] = {
|
||||
#include "nsColorNameList.h"
|
||||
};
|
||||
#undef GFX_COLOR
|
||||
|
||||
#define eColorName_COUNT (ArrayLength(kColorNames))
|
||||
#define eColorName_UNKNOWN (-1)
|
||||
|
||||
static nsStaticCaseInsensitiveNameTable* gColorTable = nullptr;
|
||||
|
||||
void nsColorNames::AddRefTable(void)
|
||||
{
|
||||
NS_ASSERTION(!gColorTable, "pre existing array!");
|
||||
if (!gColorTable) {
|
||||
gColorTable =
|
||||
new nsStaticCaseInsensitiveNameTable(kColorNames, eColorName_COUNT);
|
||||
}
|
||||
}
|
||||
|
||||
void nsColorNames::ReleaseTable(void)
|
||||
{
|
||||
if (gColorTable) {
|
||||
delete gColorTable;
|
||||
gColorTable = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static int ComponentValue(const char16_t* aColorSpec, int aLen, int color, int dpc)
|
||||
{
|
||||
int component = 0;
|
||||
int index = (color * dpc);
|
||||
if (2 < dpc) {
|
||||
dpc = 2;
|
||||
}
|
||||
while (--dpc >= 0) {
|
||||
char16_t ch = ((index < aLen) ? aColorSpec[index++] : '0');
|
||||
if (('0' <= ch) && (ch <= '9')) {
|
||||
component = (component * 16) + (ch - '0');
|
||||
} else if ((('a' <= ch) && (ch <= 'f')) ||
|
||||
(('A' <= ch) && (ch <= 'F'))) {
|
||||
// "ch&7" handles lower and uppercase hex alphabetics
|
||||
component = (component * 16) + (ch & 7) + 9;
|
||||
}
|
||||
else { // not a hex digit, treat it like 0
|
||||
component = (component * 16);
|
||||
}
|
||||
}
|
||||
return component;
|
||||
}
|
||||
|
||||
bool
|
||||
NS_HexToRGBA(const nsAString& aColorSpec, nsHexColorType aType,
|
||||
nscolor* aResult)
|
||||
{
|
||||
const char16_t* buffer = aColorSpec.BeginReading();
|
||||
|
||||
int nameLen = aColorSpec.Length();
|
||||
bool hasAlpha = false;
|
||||
if (nameLen != 3 && nameLen != 6) {
|
||||
if ((nameLen != 4 && nameLen != 8) || aType == nsHexColorType::NoAlpha) {
|
||||
// Improperly formatted color value
|
||||
return false;
|
||||
}
|
||||
hasAlpha = true;
|
||||
}
|
||||
|
||||
// Make sure the digits are legal
|
||||
for (int i = 0; i < nameLen; i++) {
|
||||
char16_t ch = buffer[i];
|
||||
if (((ch >= '0') && (ch <= '9')) ||
|
||||
((ch >= 'a') && (ch <= 'f')) ||
|
||||
((ch >= 'A') && (ch <= 'F'))) {
|
||||
// Legal character
|
||||
continue;
|
||||
}
|
||||
// Whoops. Illegal character.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert the ascii to binary
|
||||
int dpc = ((nameLen <= 4) ? 1 : 2);
|
||||
// Translate components from hex to binary
|
||||
int r = ComponentValue(buffer, nameLen, 0, dpc);
|
||||
int g = ComponentValue(buffer, nameLen, 1, dpc);
|
||||
int b = ComponentValue(buffer, nameLen, 2, dpc);
|
||||
int a;
|
||||
if (hasAlpha) {
|
||||
a = ComponentValue(buffer, nameLen, 3, dpc);
|
||||
} else {
|
||||
a = (dpc == 1) ? 0xf : 0xff;
|
||||
}
|
||||
if (dpc == 1) {
|
||||
// Scale single digit component to an 8 bit value. Replicate the
|
||||
// single digit to compute the new value.
|
||||
r = (r << 4) | r;
|
||||
g = (g << 4) | g;
|
||||
b = (b << 4) | b;
|
||||
a = (a << 4) | a;
|
||||
}
|
||||
NS_ASSERTION((r >= 0) && (r <= 255), "bad r");
|
||||
NS_ASSERTION((g >= 0) && (g <= 255), "bad g");
|
||||
NS_ASSERTION((b >= 0) && (b <= 255), "bad b");
|
||||
NS_ASSERTION((a >= 0) && (a <= 255), "bad a");
|
||||
*aResult = NS_RGBA(r, g, b, a);
|
||||
return true;
|
||||
}
|
||||
|
||||
// This implements part of the algorithm for legacy behavior described in
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/complete/common-microsyntaxes.html#rules-for-parsing-a-legacy-color-value
|
||||
bool NS_LooseHexToRGB(const nsString& aColorSpec, nscolor* aResult)
|
||||
{
|
||||
if (aColorSpec.EqualsLiteral("transparent")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int nameLen = aColorSpec.Length();
|
||||
const char16_t* colorSpec = aColorSpec.get();
|
||||
if (nameLen > 128) {
|
||||
nameLen = 128;
|
||||
}
|
||||
|
||||
if ('#' == colorSpec[0]) {
|
||||
++colorSpec;
|
||||
--nameLen;
|
||||
}
|
||||
|
||||
// digits per component
|
||||
int dpc = (nameLen + 2) / 3;
|
||||
int newdpc = dpc;
|
||||
|
||||
// Use only the rightmost 8 characters of each component.
|
||||
if (newdpc > 8) {
|
||||
nameLen -= newdpc - 8;
|
||||
colorSpec += newdpc - 8;
|
||||
newdpc = 8;
|
||||
}
|
||||
|
||||
// And then keep trimming characters at the left until we'd trim one
|
||||
// that would leave a nonzero value, but not past 2 characters per
|
||||
// component.
|
||||
while (newdpc > 2) {
|
||||
bool haveNonzero = false;
|
||||
for (int c = 0; c < 3; ++c) {
|
||||
MOZ_ASSERT(c * dpc < nameLen,
|
||||
"should not pass end of string while newdpc > 2");
|
||||
char16_t ch = colorSpec[c * dpc];
|
||||
if (('1' <= ch && ch <= '9') ||
|
||||
('A' <= ch && ch <= 'F') ||
|
||||
('a' <= ch && ch <= 'f')) {
|
||||
haveNonzero = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (haveNonzero) {
|
||||
break;
|
||||
}
|
||||
--newdpc;
|
||||
--nameLen;
|
||||
++colorSpec;
|
||||
}
|
||||
|
||||
// Translate components from hex to binary
|
||||
int r = ComponentValue(colorSpec, nameLen, 0, dpc);
|
||||
int g = ComponentValue(colorSpec, nameLen, 1, dpc);
|
||||
int b = ComponentValue(colorSpec, nameLen, 2, dpc);
|
||||
NS_ASSERTION((r >= 0) && (r <= 255), "bad r");
|
||||
NS_ASSERTION((g >= 0) && (g <= 255), "bad g");
|
||||
NS_ASSERTION((b >= 0) && (b <= 255), "bad b");
|
||||
|
||||
*aResult = NS_RGB(r, g, b);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NS_ColorNameToRGB(const nsAString& aColorName, nscolor* aResult)
|
||||
{
|
||||
if (!gColorTable) return false;
|
||||
|
||||
int32_t id = gColorTable->Lookup(aColorName);
|
||||
if (eColorName_UNKNOWN < id) {
|
||||
NS_ASSERTION(uint32_t(id) < eColorName_COUNT,
|
||||
"gColorTable->Lookup messed up");
|
||||
if (aResult) {
|
||||
*aResult = kColors[id];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns kColorNames, an array of all possible color names, and sets
|
||||
// *aSizeArray to the size of that array. Do NOT call free() on this array.
|
||||
const char * const * NS_AllColorNames(size_t *aSizeArray)
|
||||
{
|
||||
*aSizeArray = ArrayLength(kColorNames);
|
||||
return kColorNames;
|
||||
}
|
||||
|
||||
// Macro to blend two colors
|
||||
//
|
||||
// equivalent to target = (bg*(255-fgalpha) + fg*fgalpha)/255
|
||||
#define MOZ_BLEND(target, bg, fg, fgalpha) \
|
||||
FAST_DIVIDE_BY_255(target, (bg)*(255-fgalpha) + (fg)*(fgalpha))
|
||||
|
||||
nscolor
|
||||
NS_ComposeColors(nscolor aBG, nscolor aFG)
|
||||
{
|
||||
// This function uses colors that are non premultiplied alpha.
|
||||
int r, g, b, a;
|
||||
|
||||
int bgAlpha = NS_GET_A(aBG);
|
||||
int fgAlpha = NS_GET_A(aFG);
|
||||
|
||||
// Compute the final alpha of the blended color
|
||||
// a = fgAlpha + bgAlpha*(255 - fgAlpha)/255;
|
||||
FAST_DIVIDE_BY_255(a, bgAlpha*(255-fgAlpha));
|
||||
a = fgAlpha + a;
|
||||
int blendAlpha;
|
||||
if (a == 0) {
|
||||
// In this case the blended color is totally trasparent,
|
||||
// we preserve the color information of the foreground color.
|
||||
blendAlpha = 255;
|
||||
} else {
|
||||
blendAlpha = (fgAlpha*255)/a;
|
||||
}
|
||||
MOZ_BLEND(r, NS_GET_R(aBG), NS_GET_R(aFG), blendAlpha);
|
||||
MOZ_BLEND(g, NS_GET_G(aBG), NS_GET_G(aFG), blendAlpha);
|
||||
MOZ_BLEND(b, NS_GET_B(aBG), NS_GET_B(aFG), blendAlpha);
|
||||
|
||||
return NS_RGBA(r, g, b, a);
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static uint32_t
|
||||
BlendColorComponent(uint32_t aBg, uint32_t aFg, uint32_t aFgAlpha)
|
||||
{
|
||||
return RoundingDivideBy255(aBg * (255 - aFgAlpha) + aFg * aFgAlpha);
|
||||
}
|
||||
|
||||
nscolor
|
||||
LinearBlendColors(nscolor aBg, nscolor aFg, uint_fast8_t aFgRatio)
|
||||
{
|
||||
// Common case that either pure background or pure foreground
|
||||
if (aFgRatio == 0) {
|
||||
return aBg;
|
||||
}
|
||||
if (aFgRatio == 255) {
|
||||
return aFg;
|
||||
}
|
||||
// Common case that alpha channel is equal (usually both are opaque)
|
||||
if (NS_GET_A(aBg) == NS_GET_A(aFg)) {
|
||||
auto r = BlendColorComponent(NS_GET_R(aBg), NS_GET_R(aFg), aFgRatio);
|
||||
auto g = BlendColorComponent(NS_GET_G(aBg), NS_GET_G(aFg), aFgRatio);
|
||||
auto b = BlendColorComponent(NS_GET_B(aBg), NS_GET_B(aFg), aFgRatio);
|
||||
return NS_RGBA(r, g, b, NS_GET_A(aFg));
|
||||
}
|
||||
|
||||
constexpr float kFactor = 1.0f / 255.0f;
|
||||
|
||||
float p1 = kFactor * (255 - aFgRatio);
|
||||
float a1 = kFactor * NS_GET_A(aBg);
|
||||
float r1 = a1 * NS_GET_R(aBg);
|
||||
float g1 = a1 * NS_GET_G(aBg);
|
||||
float b1 = a1 * NS_GET_B(aBg);
|
||||
|
||||
float p2 = 1.0f - p1;
|
||||
float a2 = kFactor * NS_GET_A(aFg);
|
||||
float r2 = a2 * NS_GET_R(aFg);
|
||||
float g2 = a2 * NS_GET_G(aFg);
|
||||
float b2 = a2 * NS_GET_B(aFg);
|
||||
|
||||
float a = p1 * a1 + p2 * a2;
|
||||
if (a == 0.0) {
|
||||
return NS_RGBA(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
auto r = ClampColor((p1 * r1 + p2 * r2) / a);
|
||||
auto g = ClampColor((p1 * g1 + p2 * g2) / a);
|
||||
auto b = ClampColor((p1 * b1 + p2 * b2) / a);
|
||||
return NS_RGBA(r, g, b, NSToIntRound(a * 255));
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
// Functions to convert from HSL color space to RGB color space.
|
||||
// This is the algorithm described in the CSS3 specification
|
||||
|
||||
// helper
|
||||
static float
|
||||
HSL_HueToRGB(float m1, float m2, float h)
|
||||
{
|
||||
if (h < 0.0f)
|
||||
h += 1.0f;
|
||||
if (h > 1.0f)
|
||||
h -= 1.0f;
|
||||
if (h < (float)(1.0/6.0))
|
||||
return m1 + (m2 - m1)*h*6.0f;
|
||||
if (h < (float)(1.0/2.0))
|
||||
return m2;
|
||||
if (h < (float)(2.0/3.0))
|
||||
return m1 + (m2 - m1)*((float)(2.0/3.0) - h)*6.0f;
|
||||
return m1;
|
||||
}
|
||||
|
||||
// The float parameters are all expected to be in the range 0-1
|
||||
nscolor
|
||||
NS_HSL2RGB(float h, float s, float l)
|
||||
{
|
||||
uint8_t r, g, b;
|
||||
float m1, m2;
|
||||
if (l <= 0.5f) {
|
||||
m2 = l*(s+1);
|
||||
} else {
|
||||
m2 = l + s - l*s;
|
||||
}
|
||||
m1 = l*2 - m2;
|
||||
r = uint8_t(255 * HSL_HueToRGB(m1, m2, h + 1.0f/3.0f));
|
||||
g = uint8_t(255 * HSL_HueToRGB(m1, m2, h));
|
||||
b = uint8_t(255 * HSL_HueToRGB(m1, m2, h - 1.0f/3.0f));
|
||||
return NS_RGB(r, g, b);
|
||||
}
|
||||
|
||||
const char*
|
||||
NS_RGBToColorName(nscolor aColor)
|
||||
{
|
||||
for (size_t idx = 0; idx < ArrayLength(kColors); ++idx) {
|
||||
if (kColors[idx] == aColor) {
|
||||
return kColorNames[idx];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
123
gfx/src/nsColor.h
Normal file
123
gfx/src/nsColor.h
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/* -*- 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 nsColor_h___
|
||||
#define nsColor_h___
|
||||
|
||||
#include <stddef.h> // for size_t
|
||||
#include <stdint.h> // for uint8_t, uint32_t
|
||||
#include "nscore.h" // for nsAString
|
||||
#include "nsCoord.h" // for NSToIntRound
|
||||
|
||||
class nsAString;
|
||||
class nsString;
|
||||
|
||||
// A color is a 32 bit unsigned integer with four components: R, G, B
|
||||
// and A.
|
||||
typedef uint32_t nscolor;
|
||||
|
||||
// Make a color out of r,g,b values. This assumes that the r,g,b values are
|
||||
// properly constrained to 0-255. This also assumes that a is 255.
|
||||
#define NS_RGB(_r,_g,_b) \
|
||||
((nscolor) ((255 << 24) | ((_b)<<16) | ((_g)<<8) | (_r)))
|
||||
|
||||
// Make a color out of r,g,b,a values. This assumes that the r,g,b,a
|
||||
// values are properly constrained to 0-255.
|
||||
#define NS_RGBA(_r,_g,_b,_a) \
|
||||
((nscolor) (((_a) << 24) | ((_b)<<16) | ((_g)<<8) | (_r)))
|
||||
|
||||
// Extract color components from nscolor
|
||||
#define NS_GET_R(_rgba) ((uint8_t) ((_rgba) & 0xff))
|
||||
#define NS_GET_G(_rgba) ((uint8_t) (((_rgba) >> 8) & 0xff))
|
||||
#define NS_GET_B(_rgba) ((uint8_t) (((_rgba) >> 16) & 0xff))
|
||||
#define NS_GET_A(_rgba) ((uint8_t) (((_rgba) >> 24) & 0xff))
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
template<typename T>
|
||||
inline uint8_t ClampColor(T aColor)
|
||||
{
|
||||
if (aColor >= 255) {
|
||||
return 255;
|
||||
}
|
||||
if (aColor <= 0) {
|
||||
return 0;
|
||||
}
|
||||
return NSToIntRound(aColor);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
// Fast approximate division by 255. It has the property that
|
||||
// for all 0 <= n <= 255*255, FAST_DIVIDE_BY_255(n) == n/255.
|
||||
// But it only uses two adds and two shifts instead of an
|
||||
// integer division (which is expensive on many processors).
|
||||
//
|
||||
// equivalent to target=v/255
|
||||
#define FAST_DIVIDE_BY_255(target,v) \
|
||||
PR_BEGIN_MACRO \
|
||||
unsigned tmp_ = v; \
|
||||
target = ((tmp_ << 8) + tmp_ + 255) >> 16; \
|
||||
PR_END_MACRO
|
||||
|
||||
enum class nsHexColorType : uint8_t {
|
||||
NoAlpha, // 3 or 6 digit hex colors only
|
||||
AllowAlpha, // 3, 4, 6, or 8 digit hex colors
|
||||
};
|
||||
|
||||
// Translate a hex string to a color. Return true if it parses ok,
|
||||
// otherwise return false.
|
||||
// This accepts the number of digits specified by aType.
|
||||
bool
|
||||
NS_HexToRGBA(const nsAString& aBuf, nsHexColorType aType, nscolor* aResult);
|
||||
|
||||
// Compose one NS_RGB color onto another. The result is what
|
||||
// you get if you draw aFG on top of aBG with operator OVER.
|
||||
nscolor NS_ComposeColors(nscolor aBG, nscolor aFG);
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
inline uint32_t RoundingDivideBy255(uint32_t n)
|
||||
{
|
||||
// There is an approximate alternative: ((n << 8) + n + 32896) >> 16
|
||||
// But that is actually slower than this simple expression on a modern
|
||||
// machine with a modern compiler.
|
||||
return (n + 127) / 255;
|
||||
}
|
||||
|
||||
// Blend one RGBA color with another based on a given ratio.
|
||||
// It is a linear interpolation on each channel with alpha premultipled.
|
||||
nscolor LinearBlendColors(nscolor aBg, nscolor aFg, uint_fast8_t aFgRatio);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
// Translate a hex string to a color. Return true if it parses ok,
|
||||
// otherwise return false.
|
||||
// This version accepts 1 to 9 digits (missing digits are 0)
|
||||
bool NS_LooseHexToRGB(const nsString& aBuf, nscolor* aResult);
|
||||
|
||||
// There is no function to translate a color to a hex string, because
|
||||
// the hex-string syntax does not support transparency.
|
||||
|
||||
// Translate a color name to a color. Return true if it parses ok,
|
||||
// otherwise return false.
|
||||
bool NS_ColorNameToRGB(const nsAString& aBuf, nscolor* aResult);
|
||||
|
||||
// Returns an array of all possible color names, and sets
|
||||
// *aSizeArray to the size of that array. Do NOT call |free()| on this array.
|
||||
const char * const * NS_AllColorNames(size_t *aSizeArray);
|
||||
|
||||
// function to convert from HSL color space to RGB color space
|
||||
// the float parameters are all expected to be in the range 0-1
|
||||
nscolor NS_HSL2RGB(float h, float s, float l);
|
||||
|
||||
// Return a color name for the given nscolor. If there is no color
|
||||
// name for it, returns null. If there are multiple possible color
|
||||
// names for the given color, the first one in nsColorNameList.h
|
||||
// (which is generally the first one in alphabetical order) will be
|
||||
// returned.
|
||||
const char* NS_RGBToColorName(nscolor aColor);
|
||||
|
||||
#endif /* nsColor_h___ */
|
||||
181
gfx/src/nsColorNameList.h
Normal file
181
gfx/src/nsColorNameList.h
Normal 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/. */
|
||||
|
||||
/******
|
||||
|
||||
This file contains the list of all named colors
|
||||
See nsCSSColorNames.h for access to the enum values for colors
|
||||
|
||||
It is designed to be used as inline input to nsCSSColorNames.cpp *only*
|
||||
through the magic of C preprocessing.
|
||||
|
||||
All entries must be enclosed in the macro GFX_COLOR which will have cruel
|
||||
and unusual things done to it
|
||||
|
||||
It is recommended (but not strictly necessary) to keep all entries
|
||||
in alphabetical order
|
||||
|
||||
The first argument to GFX_COLOR is both the enum identifier of the color
|
||||
and the string value
|
||||
The second argument is the sRGBA value for the named color
|
||||
|
||||
'name' entries *must* use only lowercase characters.
|
||||
|
||||
** Break these invarient and bad things will happen. **
|
||||
|
||||
|
||||
******/
|
||||
|
||||
|
||||
GFX_COLOR(aliceblue, NS_RGB(240, 248, 255))
|
||||
GFX_COLOR(antiquewhite, NS_RGB(250, 235, 215))
|
||||
GFX_COLOR(aqua, NS_RGB( 0, 255, 255))
|
||||
GFX_COLOR(aquamarine, NS_RGB(127, 255, 212))
|
||||
GFX_COLOR(azure, NS_RGB(240, 255, 255))
|
||||
GFX_COLOR(beige, NS_RGB(245, 245, 220))
|
||||
GFX_COLOR(bisque, NS_RGB(255, 228, 196))
|
||||
GFX_COLOR(black, NS_RGB( 0, 0, 0))
|
||||
GFX_COLOR(blanchedalmond, NS_RGB(255, 235, 205))
|
||||
GFX_COLOR(blue, NS_RGB( 0, 0, 255))
|
||||
GFX_COLOR(blueviolet, NS_RGB(138, 43, 226))
|
||||
GFX_COLOR(brown, NS_RGB(165, 42, 42))
|
||||
GFX_COLOR(burlywood, NS_RGB(222, 184, 135))
|
||||
GFX_COLOR(cadetblue, NS_RGB( 95, 158, 160))
|
||||
GFX_COLOR(chartreuse, NS_RGB(127, 255, 0))
|
||||
GFX_COLOR(chocolate, NS_RGB(210, 105, 30))
|
||||
GFX_COLOR(coral, NS_RGB(255, 127, 80))
|
||||
GFX_COLOR(cornflowerblue, NS_RGB(100, 149, 237))
|
||||
GFX_COLOR(cornsilk, NS_RGB(255, 248, 220))
|
||||
GFX_COLOR(crimson, NS_RGB(220, 20, 60))
|
||||
GFX_COLOR(cyan, NS_RGB( 0, 255, 255))
|
||||
GFX_COLOR(darkblue, NS_RGB( 0, 0, 139))
|
||||
GFX_COLOR(darkcyan, NS_RGB( 0, 139, 139))
|
||||
GFX_COLOR(darkgoldenrod, NS_RGB(184, 134, 11))
|
||||
GFX_COLOR(darkgray, NS_RGB(169, 169, 169))
|
||||
GFX_COLOR(darkgreen, NS_RGB( 0, 100, 0))
|
||||
GFX_COLOR(darkgrey, NS_RGB(169, 169, 169))
|
||||
GFX_COLOR(darkkhaki, NS_RGB(189, 183, 107))
|
||||
GFX_COLOR(darkmagenta, NS_RGB(139, 0, 139))
|
||||
GFX_COLOR(darkolivegreen, NS_RGB( 85, 107, 47))
|
||||
GFX_COLOR(darkorange, NS_RGB(255, 140, 0))
|
||||
GFX_COLOR(darkorchid, NS_RGB(153, 50, 204))
|
||||
GFX_COLOR(darkred, NS_RGB(139, 0, 0))
|
||||
GFX_COLOR(darksalmon, NS_RGB(233, 150, 122))
|
||||
GFX_COLOR(darkseagreen, NS_RGB(143, 188, 143))
|
||||
GFX_COLOR(darkslateblue, NS_RGB( 72, 61, 139))
|
||||
GFX_COLOR(darkslategray, NS_RGB( 47, 79, 79))
|
||||
GFX_COLOR(darkslategrey, NS_RGB( 47, 79, 79))
|
||||
GFX_COLOR(darkturquoise, NS_RGB( 0, 206, 209))
|
||||
GFX_COLOR(darkviolet, NS_RGB(148, 0, 211))
|
||||
GFX_COLOR(deeppink, NS_RGB(255, 20, 147))
|
||||
GFX_COLOR(deepskyblue, NS_RGB( 0, 191, 255))
|
||||
GFX_COLOR(dimgray, NS_RGB(105, 105, 105))
|
||||
GFX_COLOR(dimgrey, NS_RGB(105, 105, 105))
|
||||
GFX_COLOR(dodgerblue, NS_RGB( 30, 144, 255))
|
||||
GFX_COLOR(firebrick, NS_RGB(178, 34, 34))
|
||||
GFX_COLOR(floralwhite, NS_RGB(255, 250, 240))
|
||||
GFX_COLOR(forestgreen, NS_RGB( 34, 139, 34))
|
||||
GFX_COLOR(fuchsia, NS_RGB(255, 0, 255))
|
||||
GFX_COLOR(gainsboro, NS_RGB(220, 220, 220))
|
||||
GFX_COLOR(ghostwhite, NS_RGB(248, 248, 255))
|
||||
GFX_COLOR(gold, NS_RGB(255, 215, 0))
|
||||
GFX_COLOR(goldenrod, NS_RGB(218, 165, 32))
|
||||
GFX_COLOR(gray, NS_RGB(128, 128, 128))
|
||||
GFX_COLOR(grey, NS_RGB(128, 128, 128))
|
||||
GFX_COLOR(green, NS_RGB( 0, 128, 0))
|
||||
GFX_COLOR(greenyellow, NS_RGB(173, 255, 47))
|
||||
GFX_COLOR(honeydew, NS_RGB(240, 255, 240))
|
||||
GFX_COLOR(hotpink, NS_RGB(255, 105, 180))
|
||||
GFX_COLOR(indianred, NS_RGB(205, 92, 92))
|
||||
GFX_COLOR(indigo, NS_RGB( 75, 0, 130))
|
||||
GFX_COLOR(ivory, NS_RGB(255, 255, 240))
|
||||
GFX_COLOR(khaki, NS_RGB(240, 230, 140))
|
||||
GFX_COLOR(lavender, NS_RGB(230, 230, 250))
|
||||
GFX_COLOR(lavenderblush, NS_RGB(255, 240, 245))
|
||||
GFX_COLOR(lawngreen, NS_RGB(124, 252, 0))
|
||||
GFX_COLOR(lemonchiffon, NS_RGB(255, 250, 205))
|
||||
GFX_COLOR(lightblue, NS_RGB(173, 216, 230))
|
||||
GFX_COLOR(lightcoral, NS_RGB(240, 128, 128))
|
||||
GFX_COLOR(lightcyan, NS_RGB(224, 255, 255))
|
||||
GFX_COLOR(lightgoldenrodyellow, NS_RGB(250, 250, 210))
|
||||
GFX_COLOR(lightgray, NS_RGB(211, 211, 211))
|
||||
GFX_COLOR(lightgreen, NS_RGB(144, 238, 144))
|
||||
GFX_COLOR(lightgrey, NS_RGB(211, 211, 211))
|
||||
GFX_COLOR(lightpink, NS_RGB(255, 182, 193))
|
||||
GFX_COLOR(lightsalmon, NS_RGB(255, 160, 122))
|
||||
GFX_COLOR(lightseagreen, NS_RGB( 32, 178, 170))
|
||||
GFX_COLOR(lightskyblue, NS_RGB(135, 206, 250))
|
||||
GFX_COLOR(lightslategray, NS_RGB(119, 136, 153))
|
||||
GFX_COLOR(lightslategrey, NS_RGB(119, 136, 153))
|
||||
GFX_COLOR(lightsteelblue, NS_RGB(176, 196, 222))
|
||||
GFX_COLOR(lightyellow, NS_RGB(255, 255, 224))
|
||||
GFX_COLOR(lime, NS_RGB( 0, 255, 0))
|
||||
GFX_COLOR(limegreen, NS_RGB( 50, 205, 50))
|
||||
GFX_COLOR(linen, NS_RGB(250, 240, 230))
|
||||
GFX_COLOR(magenta, NS_RGB(255, 0, 255))
|
||||
GFX_COLOR(maroon, NS_RGB(128, 0, 0))
|
||||
GFX_COLOR(mediumaquamarine, NS_RGB(102, 205, 170))
|
||||
GFX_COLOR(mediumblue, NS_RGB( 0, 0, 205))
|
||||
GFX_COLOR(mediumorchid, NS_RGB(186, 85, 211))
|
||||
GFX_COLOR(mediumpurple, NS_RGB(147, 112, 219))
|
||||
GFX_COLOR(mediumseagreen, NS_RGB( 60, 179, 113))
|
||||
GFX_COLOR(mediumslateblue, NS_RGB(123, 104, 238))
|
||||
GFX_COLOR(mediumspringgreen, NS_RGB( 0, 250, 154))
|
||||
GFX_COLOR(mediumturquoise, NS_RGB( 72, 209, 204))
|
||||
GFX_COLOR(mediumvioletred, NS_RGB(199, 21, 133))
|
||||
GFX_COLOR(midnightblue, NS_RGB( 25, 25, 112))
|
||||
GFX_COLOR(mintcream, NS_RGB(245, 255, 250))
|
||||
GFX_COLOR(mistyrose, NS_RGB(255, 228, 225))
|
||||
GFX_COLOR(moccasin, NS_RGB(255, 228, 181))
|
||||
GFX_COLOR(navajowhite, NS_RGB(255, 222, 173))
|
||||
GFX_COLOR(navy, NS_RGB( 0, 0, 128))
|
||||
GFX_COLOR(oldlace, NS_RGB(253, 245, 230))
|
||||
GFX_COLOR(olive, NS_RGB(128, 128, 0))
|
||||
GFX_COLOR(olivedrab, NS_RGB(107, 142, 35))
|
||||
GFX_COLOR(orange, NS_RGB(255, 165, 0))
|
||||
GFX_COLOR(orangered, NS_RGB(255, 69, 0))
|
||||
GFX_COLOR(orchid, NS_RGB(218, 112, 214))
|
||||
GFX_COLOR(palegoldenrod, NS_RGB(238, 232, 170))
|
||||
GFX_COLOR(palegreen, NS_RGB(152, 251, 152))
|
||||
GFX_COLOR(paleturquoise, NS_RGB(175, 238, 238))
|
||||
GFX_COLOR(palevioletred, NS_RGB(219, 112, 147))
|
||||
GFX_COLOR(papayawhip, NS_RGB(255, 239, 213))
|
||||
GFX_COLOR(peachpuff, NS_RGB(255, 218, 185))
|
||||
GFX_COLOR(peru, NS_RGB(205, 133, 63))
|
||||
GFX_COLOR(pink, NS_RGB(255, 192, 203))
|
||||
GFX_COLOR(plum, NS_RGB(221, 160, 221))
|
||||
GFX_COLOR(powderblue, NS_RGB(176, 224, 230))
|
||||
GFX_COLOR(purple, NS_RGB(128, 0, 128))
|
||||
GFX_COLOR(rebeccapurple, NS_RGB(102, 51, 153))
|
||||
GFX_COLOR(red, NS_RGB(255, 0, 0))
|
||||
GFX_COLOR(rosybrown, NS_RGB(188, 143, 143))
|
||||
GFX_COLOR(royalblue, NS_RGB( 65, 105, 225))
|
||||
GFX_COLOR(saddlebrown, NS_RGB(139, 69, 19))
|
||||
GFX_COLOR(salmon, NS_RGB(250, 128, 114))
|
||||
GFX_COLOR(sandybrown, NS_RGB(244, 164, 96))
|
||||
GFX_COLOR(seagreen, NS_RGB( 46, 139, 87))
|
||||
GFX_COLOR(seashell, NS_RGB(255, 245, 238))
|
||||
GFX_COLOR(sienna, NS_RGB(160, 82, 45))
|
||||
GFX_COLOR(silver, NS_RGB(192, 192, 192))
|
||||
GFX_COLOR(skyblue, NS_RGB(135, 206, 235))
|
||||
GFX_COLOR(slateblue, NS_RGB(106, 90, 205))
|
||||
GFX_COLOR(slategray, NS_RGB(112, 128, 144))
|
||||
GFX_COLOR(slategrey, NS_RGB(112, 128, 144))
|
||||
GFX_COLOR(snow, NS_RGB(255, 250, 250))
|
||||
GFX_COLOR(springgreen, NS_RGB( 0, 255, 127))
|
||||
GFX_COLOR(steelblue, NS_RGB( 70, 130, 180))
|
||||
GFX_COLOR(tan, NS_RGB(210, 180, 140))
|
||||
GFX_COLOR(teal, NS_RGB( 0, 128, 128))
|
||||
GFX_COLOR(thistle, NS_RGB(216, 191, 216))
|
||||
GFX_COLOR(tomato, NS_RGB(255, 99, 71))
|
||||
GFX_COLOR(transparent, NS_RGBA(0, 0, 0, 0))
|
||||
GFX_COLOR(turquoise, NS_RGB( 64, 224, 208))
|
||||
GFX_COLOR(violet, NS_RGB(238, 130, 238))
|
||||
GFX_COLOR(wheat, NS_RGB(245, 222, 179))
|
||||
GFX_COLOR(white, NS_RGB(255, 255, 255))
|
||||
GFX_COLOR(whitesmoke, NS_RGB(245, 245, 245))
|
||||
GFX_COLOR(yellow, NS_RGB(255, 255, 0))
|
||||
GFX_COLOR(yellowgreen, NS_RGB(154, 205, 50))
|
||||
|
||||
16
gfx/src/nsColorNames.h
Normal file
16
gfx/src/nsColorNames.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/* -*- 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 nsColorNames_h___
|
||||
#define nsColorNames_h___
|
||||
|
||||
|
||||
class nsColorNames {
|
||||
public:
|
||||
static void AddRefTable(void);
|
||||
static void ReleaseTable(void);
|
||||
};
|
||||
|
||||
#endif /* nsColorNames_h___ */
|
||||
443
gfx/src/nsCoord.h
Normal file
443
gfx/src/nsCoord.h
Normal file
|
|
@ -0,0 +1,443 @@
|
|||
/* -*- 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 NSCOORD_H
|
||||
#define NSCOORD_H
|
||||
|
||||
#include "nsAlgorithm.h"
|
||||
#include "nscore.h"
|
||||
#include "nsMathUtils.h"
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "nsDebug.h"
|
||||
#include <algorithm>
|
||||
|
||||
/*
|
||||
* Basic type used for the geometry classes.
|
||||
*
|
||||
* Normally all coordinates are maintained in an app unit coordinate
|
||||
* space. An app unit is 1/60th of a CSS device pixel, which is, in turn
|
||||
* an integer number of device pixels, such at the CSS DPI is as close to
|
||||
* 96dpi as possible.
|
||||
*/
|
||||
|
||||
// This controls whether we're using integers or floats for coordinates. We
|
||||
// want to eventually use floats.
|
||||
//#define NS_COORD_IS_FLOAT
|
||||
|
||||
inline float NS_IEEEPositiveInfinity() {
|
||||
union { uint32_t mPRUint32; float mFloat; } pun;
|
||||
pun.mPRUint32 = 0x7F800000;
|
||||
return pun.mFloat;
|
||||
}
|
||||
inline bool NS_IEEEIsNan(float aF) {
|
||||
union { uint32_t mBits; float mFloat; } pun;
|
||||
pun.mFloat = aF;
|
||||
return (pun.mBits & 0x7F800000) == 0x7F800000 &&
|
||||
(pun.mBits & 0x007FFFFF) != 0;
|
||||
}
|
||||
|
||||
#ifdef NS_COORD_IS_FLOAT
|
||||
typedef float nscoord;
|
||||
#define nscoord_MAX NS_IEEEPositiveInfinity()
|
||||
#else
|
||||
typedef int32_t nscoord;
|
||||
#define nscoord_MAX nscoord(1 << 30)
|
||||
#endif
|
||||
|
||||
#define nscoord_MIN (-nscoord_MAX)
|
||||
|
||||
inline void VERIFY_COORD(nscoord aCoord) {
|
||||
#ifdef NS_COORD_IS_FLOAT
|
||||
NS_ASSERTION(floorf(aCoord) == aCoord,
|
||||
"Coords cannot have fractions");
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Divide aSpace by aN. Assign the resulting quotient to aQuotient and
|
||||
* return the remainder.
|
||||
*/
|
||||
inline nscoord NSCoordDivRem(nscoord aSpace, size_t aN, nscoord* aQuotient)
|
||||
{
|
||||
#ifdef NS_COORD_IS_FLOAT
|
||||
*aQuotient = aSpace / aN;
|
||||
return 0.0f;
|
||||
#else
|
||||
div_t result = div(aSpace, aN);
|
||||
*aQuotient = nscoord(result.quot);
|
||||
return nscoord(result.rem);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline nscoord NSCoordMulDiv(nscoord aMult1, nscoord aMult2, nscoord aDiv) {
|
||||
#ifdef NS_COORD_IS_FLOAT
|
||||
return (aMult1 * aMult2 / aDiv);
|
||||
#else
|
||||
return (int64_t(aMult1) * int64_t(aMult2) / int64_t(aDiv));
|
||||
#endif
|
||||
}
|
||||
|
||||
inline nscoord NSToCoordRound(float aValue)
|
||||
{
|
||||
#if defined(XP_WIN32) && defined(_M_IX86) && !defined(__GNUC__) && !defined(__clang__)
|
||||
return NS_lroundup30(aValue);
|
||||
#else
|
||||
return nscoord(floorf(aValue + 0.5f));
|
||||
#endif /* XP_WIN32 && _M_IX86 && !__GNUC__ */
|
||||
}
|
||||
|
||||
inline nscoord NSToCoordRound(double aValue)
|
||||
{
|
||||
#if defined(XP_WIN32) && defined(_M_IX86) && !defined(__GNUC__) && !defined(__clang__)
|
||||
return NS_lroundup30((float)aValue);
|
||||
#else
|
||||
return nscoord(floor(aValue + 0.5f));
|
||||
#endif /* XP_WIN32 && _M_IX86 && !__GNUC__ */
|
||||
}
|
||||
|
||||
inline nscoord NSToCoordRoundWithClamp(float aValue)
|
||||
{
|
||||
#ifndef NS_COORD_IS_FLOAT
|
||||
// Bounds-check before converting out of float, to avoid overflow
|
||||
if (aValue >= nscoord_MAX) {
|
||||
return nscoord_MAX;
|
||||
}
|
||||
if (aValue <= nscoord_MIN) {
|
||||
return nscoord_MIN;
|
||||
}
|
||||
#endif
|
||||
return NSToCoordRound(aValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns aCoord * aScale, capping the product to nscoord_MAX or nscoord_MIN as
|
||||
* appropriate for the signs of aCoord and aScale. If requireNotNegative is
|
||||
* true, this method will enforce that aScale is not negative; use that
|
||||
* parametrization to get a check of that fact in debug builds.
|
||||
*/
|
||||
inline nscoord _nscoordSaturatingMultiply(nscoord aCoord, float aScale,
|
||||
bool requireNotNegative) {
|
||||
VERIFY_COORD(aCoord);
|
||||
if (requireNotNegative) {
|
||||
MOZ_ASSERT(aScale >= 0.0f,
|
||||
"negative scaling factors must be handled manually");
|
||||
}
|
||||
#ifdef NS_COORD_IS_FLOAT
|
||||
return floorf(aCoord * aScale);
|
||||
#else
|
||||
float product = aCoord * aScale;
|
||||
if (requireNotNegative ? aCoord > 0 : (aCoord > 0) == (aScale > 0))
|
||||
return NSToCoordRoundWithClamp(std::min<float>(nscoord_MAX, product));
|
||||
return NSToCoordRoundWithClamp(std::max<float>(nscoord_MIN, product));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns aCoord * aScale, capping the product to nscoord_MAX or nscoord_MIN as
|
||||
* appropriate for the sign of aCoord. This method requires aScale to not be
|
||||
* negative; use this method when you know that aScale should never be
|
||||
* negative to get a sanity check of that invariant in debug builds.
|
||||
*/
|
||||
inline nscoord NSCoordSaturatingNonnegativeMultiply(nscoord aCoord, float aScale) {
|
||||
return _nscoordSaturatingMultiply(aCoord, aScale, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns aCoord * aScale, capping the product to nscoord_MAX or nscoord_MIN as
|
||||
* appropriate for the signs of aCoord and aScale.
|
||||
*/
|
||||
inline nscoord NSCoordSaturatingMultiply(nscoord aCoord, float aScale) {
|
||||
return _nscoordSaturatingMultiply(aCoord, aScale, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a + b, capping the sum to nscoord_MAX.
|
||||
*
|
||||
* This function assumes that neither argument is nscoord_MIN.
|
||||
*
|
||||
* Note: If/when we start using floats for nscoords, this function won't be as
|
||||
* necessary. Normal float addition correctly handles adding with infinity,
|
||||
* assuming we aren't adding nscoord_MIN. (-infinity)
|
||||
*/
|
||||
inline nscoord
|
||||
NSCoordSaturatingAdd(nscoord a, nscoord b)
|
||||
{
|
||||
VERIFY_COORD(a);
|
||||
VERIFY_COORD(b);
|
||||
|
||||
#ifdef NS_COORD_IS_FLOAT
|
||||
// Float math correctly handles a+b, given that neither is -infinity.
|
||||
return a + b;
|
||||
#else
|
||||
if (a == nscoord_MAX || b == nscoord_MAX) {
|
||||
// infinity + anything = anything + infinity = infinity
|
||||
return nscoord_MAX;
|
||||
} else {
|
||||
// a + b = a + b
|
||||
// Cap the result, just in case we're dealing with numbers near nscoord_MAX
|
||||
return std::min(nscoord_MAX, a + b);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a - b, gracefully handling cases involving nscoord_MAX.
|
||||
* This function assumes that neither argument is nscoord_MIN.
|
||||
*
|
||||
* The behavior is as follows:
|
||||
*
|
||||
* a) infinity - infinity -> infMinusInfResult
|
||||
* b) N - infinity -> 0 (unexpected -- triggers NOTREACHED)
|
||||
* c) infinity - N -> infinity
|
||||
* d) N1 - N2 -> N1 - N2
|
||||
*
|
||||
* Note: For float nscoords, cases (c) and (d) are handled by normal float
|
||||
* math. We still need to explicitly specify the behavior for cases (a)
|
||||
* and (b), though. (Under normal float math, those cases would return NaN
|
||||
* and -infinity, respectively.)
|
||||
*/
|
||||
inline nscoord
|
||||
NSCoordSaturatingSubtract(nscoord a, nscoord b,
|
||||
nscoord infMinusInfResult)
|
||||
{
|
||||
VERIFY_COORD(a);
|
||||
VERIFY_COORD(b);
|
||||
|
||||
if (b == nscoord_MAX) {
|
||||
if (a == nscoord_MAX) {
|
||||
// case (a)
|
||||
return infMinusInfResult;
|
||||
} else {
|
||||
// case (b)
|
||||
NS_NOTREACHED("Attempted to subtract [n - nscoord_MAX]");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
#ifdef NS_COORD_IS_FLOAT
|
||||
// case (c) and (d) for floats. (float math handles both)
|
||||
return a - b;
|
||||
#else
|
||||
if (a == nscoord_MAX) {
|
||||
// case (c) for integers
|
||||
return nscoord_MAX;
|
||||
} else {
|
||||
// case (d) for integers
|
||||
// Cap the result, in case we're dealing with numbers near nscoord_MAX
|
||||
return std::min(nscoord_MAX, a - b);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
inline float NSCoordToFloat(nscoord aCoord) {
|
||||
VERIFY_COORD(aCoord);
|
||||
#ifdef NS_COORD_IS_FLOAT
|
||||
NS_ASSERTION(!NS_IEEEIsNan(aCoord), "NaN encountered in float conversion");
|
||||
#endif
|
||||
return (float)aCoord;
|
||||
}
|
||||
|
||||
/*
|
||||
* Coord Rounding Functions
|
||||
*/
|
||||
inline nscoord NSToCoordFloor(float aValue)
|
||||
{
|
||||
return nscoord(floorf(aValue));
|
||||
}
|
||||
|
||||
inline nscoord NSToCoordFloor(double aValue)
|
||||
{
|
||||
return nscoord(floor(aValue));
|
||||
}
|
||||
|
||||
inline nscoord NSToCoordFloorClamped(float aValue)
|
||||
{
|
||||
#ifndef NS_COORD_IS_FLOAT
|
||||
// Bounds-check before converting out of float, to avoid overflow
|
||||
if (aValue >= nscoord_MAX) {
|
||||
return nscoord_MAX;
|
||||
}
|
||||
if (aValue <= nscoord_MIN) {
|
||||
return nscoord_MIN;
|
||||
}
|
||||
#endif
|
||||
return NSToCoordFloor(aValue);
|
||||
}
|
||||
|
||||
inline nscoord NSToCoordCeil(float aValue)
|
||||
{
|
||||
return nscoord(ceilf(aValue));
|
||||
}
|
||||
|
||||
inline nscoord NSToCoordCeil(double aValue)
|
||||
{
|
||||
return nscoord(ceil(aValue));
|
||||
}
|
||||
|
||||
inline nscoord NSToCoordCeilClamped(double aValue)
|
||||
{
|
||||
#ifndef NS_COORD_IS_FLOAT
|
||||
// Bounds-check before converting out of double, to avoid overflow
|
||||
if (aValue >= nscoord_MAX) {
|
||||
return nscoord_MAX;
|
||||
}
|
||||
if (aValue <= nscoord_MIN) {
|
||||
return nscoord_MIN;
|
||||
}
|
||||
#endif
|
||||
return NSToCoordCeil(aValue);
|
||||
}
|
||||
|
||||
// The NSToCoordTrunc* functions remove the fractional component of
|
||||
// aValue, and are thus equivalent to NSToCoordFloor* for positive
|
||||
// values and NSToCoordCeil* for negative values.
|
||||
|
||||
inline nscoord NSToCoordTrunc(float aValue)
|
||||
{
|
||||
// There's no need to use truncf() since it matches the default
|
||||
// rules for float to integer conversion.
|
||||
return nscoord(aValue);
|
||||
}
|
||||
|
||||
inline nscoord NSToCoordTrunc(double aValue)
|
||||
{
|
||||
// There's no need to use trunc() since it matches the default
|
||||
// rules for float to integer conversion.
|
||||
return nscoord(aValue);
|
||||
}
|
||||
|
||||
inline nscoord NSToCoordTruncClamped(float aValue)
|
||||
{
|
||||
#ifndef NS_COORD_IS_FLOAT
|
||||
// Bounds-check before converting out of float, to avoid overflow
|
||||
if (aValue >= nscoord_MAX) {
|
||||
return nscoord_MAX;
|
||||
}
|
||||
if (aValue <= nscoord_MIN) {
|
||||
return nscoord_MIN;
|
||||
}
|
||||
#endif
|
||||
return NSToCoordTrunc(aValue);
|
||||
}
|
||||
|
||||
inline nscoord NSToCoordTruncClamped(double aValue)
|
||||
{
|
||||
#ifndef NS_COORD_IS_FLOAT
|
||||
// Bounds-check before converting out of double, to avoid overflow
|
||||
if (aValue >= nscoord_MAX) {
|
||||
return nscoord_MAX;
|
||||
}
|
||||
if (aValue <= nscoord_MIN) {
|
||||
return nscoord_MIN;
|
||||
}
|
||||
#endif
|
||||
return NSToCoordTrunc(aValue);
|
||||
}
|
||||
|
||||
/*
|
||||
* Int Rounding Functions
|
||||
*/
|
||||
inline int32_t NSToIntFloor(float aValue)
|
||||
{
|
||||
return int32_t(floorf(aValue));
|
||||
}
|
||||
|
||||
inline int32_t NSToIntCeil(float aValue)
|
||||
{
|
||||
return int32_t(ceilf(aValue));
|
||||
}
|
||||
|
||||
inline int32_t NSToIntRound(float aValue)
|
||||
{
|
||||
return NS_lroundf(aValue);
|
||||
}
|
||||
|
||||
inline int32_t NSToIntRound(double aValue)
|
||||
{
|
||||
return NS_lround(aValue);
|
||||
}
|
||||
|
||||
inline int32_t NSToIntRoundUp(double aValue)
|
||||
{
|
||||
return int32_t(floor(aValue + 0.5));
|
||||
}
|
||||
|
||||
/*
|
||||
* App Unit/Pixel conversions
|
||||
*/
|
||||
inline nscoord NSFloatPixelsToAppUnits(float aPixels, float aAppUnitsPerPixel)
|
||||
{
|
||||
return NSToCoordRoundWithClamp(aPixels * aAppUnitsPerPixel);
|
||||
}
|
||||
|
||||
inline nscoord NSIntPixelsToAppUnits(int32_t aPixels, int32_t aAppUnitsPerPixel)
|
||||
{
|
||||
// The cast to nscoord makes sure we don't overflow if we ever change
|
||||
// nscoord to float
|
||||
nscoord r = aPixels * (nscoord)aAppUnitsPerPixel;
|
||||
VERIFY_COORD(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline float NSAppUnitsToFloatPixels(nscoord aAppUnits, float aAppUnitsPerPixel)
|
||||
{
|
||||
return (float(aAppUnits) / aAppUnitsPerPixel);
|
||||
}
|
||||
|
||||
inline double NSAppUnitsToDoublePixels(nscoord aAppUnits, double aAppUnitsPerPixel)
|
||||
{
|
||||
return (double(aAppUnits) / aAppUnitsPerPixel);
|
||||
}
|
||||
|
||||
inline int32_t NSAppUnitsToIntPixels(nscoord aAppUnits, float aAppUnitsPerPixel)
|
||||
{
|
||||
return NSToIntRound(float(aAppUnits) / aAppUnitsPerPixel);
|
||||
}
|
||||
|
||||
inline float NSCoordScale(nscoord aCoord, int32_t aFromAPP, int32_t aToAPP)
|
||||
{
|
||||
return (NSCoordToFloat(aCoord) * aToAPP) / aFromAPP;
|
||||
}
|
||||
|
||||
/// handy constants
|
||||
#define TWIPS_PER_POINT_INT 20
|
||||
#define TWIPS_PER_POINT_FLOAT 20.0f
|
||||
#define POINTS_PER_INCH_INT 72
|
||||
#define POINTS_PER_INCH_FLOAT 72.0f
|
||||
#define CM_PER_INCH_FLOAT 2.54f
|
||||
#define MM_PER_INCH_FLOAT 25.4f
|
||||
|
||||
/*
|
||||
* Twips/unit conversions
|
||||
*/
|
||||
inline float NSUnitsToTwips(float aValue, float aPointsPerUnit)
|
||||
{
|
||||
return aValue * aPointsPerUnit * TWIPS_PER_POINT_FLOAT;
|
||||
}
|
||||
|
||||
inline float NSTwipsToUnits(float aTwips, float aUnitsPerPoint)
|
||||
{
|
||||
return (aTwips * (aUnitsPerPoint / TWIPS_PER_POINT_FLOAT));
|
||||
}
|
||||
|
||||
/// Unit conversion macros
|
||||
//@{
|
||||
#define NS_POINTS_TO_TWIPS(x) NSUnitsToTwips((x), 1.0f)
|
||||
#define NS_INCHES_TO_TWIPS(x) NSUnitsToTwips((x), POINTS_PER_INCH_FLOAT) // 72 points per inch
|
||||
|
||||
#define NS_MILLIMETERS_TO_TWIPS(x) NSUnitsToTwips((x), (POINTS_PER_INCH_FLOAT * 0.03937f))
|
||||
|
||||
#define NS_POINTS_TO_INT_TWIPS(x) NSToIntRound(NS_POINTS_TO_TWIPS(x))
|
||||
#define NS_INCHES_TO_INT_TWIPS(x) NSToIntRound(NS_INCHES_TO_TWIPS(x))
|
||||
|
||||
#define NS_TWIPS_TO_INCHES(x) NSTwipsToUnits((x), 1.0f / POINTS_PER_INCH_FLOAT)
|
||||
|
||||
#define NS_TWIPS_TO_MILLIMETERS(x) NSTwipsToUnits((x), 1.0f / (POINTS_PER_INCH_FLOAT * 0.03937f))
|
||||
//@}
|
||||
|
||||
#endif /* NSCOORD_H */
|
||||
725
gfx/src/nsDeviceContext.cpp
Normal file
725
gfx/src/nsDeviceContext.cpp
Normal file
|
|
@ -0,0 +1,725 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set sw=4 ts=4 expandtab: */
|
||||
/* 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 "nsDeviceContext.h"
|
||||
#include <algorithm> // for max
|
||||
#include "gfxASurface.h" // for gfxASurface, etc
|
||||
#include "gfxContext.h"
|
||||
#include "gfxFont.h" // for gfxFontGroup
|
||||
#include "gfxImageSurface.h" // for gfxImageSurface
|
||||
#include "gfxPoint.h" // for gfxSize
|
||||
#include "mozilla/Attributes.h" // for final
|
||||
#include "mozilla/gfx/PathHelpers.h"
|
||||
#include "mozilla/gfx/PrintTarget.h"
|
||||
#include "mozilla/Preferences.h" // for Preferences
|
||||
#include "mozilla/Services.h" // for GetObserverService
|
||||
#include "mozilla/mozalloc.h" // for operator new
|
||||
#include "nsCRT.h" // for nsCRT
|
||||
#include "nsDebug.h" // for NS_NOTREACHED, NS_ASSERTION, etc
|
||||
#include "nsFont.h" // for nsFont
|
||||
#include "nsFontMetrics.h" // for nsFontMetrics
|
||||
#include "nsIAtom.h" // for nsIAtom, NS_Atomize
|
||||
#include "nsID.h"
|
||||
#include "nsIDeviceContextSpec.h" // for nsIDeviceContextSpec
|
||||
#include "nsILanguageAtomService.h" // for nsILanguageAtomService, etc
|
||||
#include "nsIObserver.h" // for nsIObserver, etc
|
||||
#include "nsIObserverService.h" // for nsIObserverService
|
||||
#include "nsIScreen.h" // for nsIScreen
|
||||
#include "nsIScreenManager.h" // for nsIScreenManager
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE
|
||||
#include "nsIWidget.h" // for nsIWidget, NS_NATIVE_WINDOW
|
||||
#include "nsRect.h" // for nsRect
|
||||
#include "nsServiceManagerUtils.h" // for do_GetService
|
||||
#include "nsString.h" // for nsDependentString
|
||||
#include "nsTArray.h" // for nsTArray, nsTArray_Impl
|
||||
#include "nsThreadUtils.h" // for NS_IsMainThread
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
using mozilla::services::GetObserverService;
|
||||
|
||||
class nsFontCache final : public nsIObserver
|
||||
{
|
||||
public:
|
||||
nsFontCache() { MOZ_COUNT_CTOR(nsFontCache); }
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
void Init(nsDeviceContext* aContext);
|
||||
void Destroy();
|
||||
|
||||
already_AddRefed<nsFontMetrics> GetMetricsFor(
|
||||
const nsFont& aFont, const nsFontMetrics::Params& aParams);
|
||||
|
||||
void FontMetricsDeleted(const nsFontMetrics* aFontMetrics);
|
||||
void Compact();
|
||||
void Flush();
|
||||
|
||||
protected:
|
||||
~nsFontCache() { MOZ_COUNT_DTOR(nsFontCache); }
|
||||
|
||||
nsDeviceContext* mContext; // owner
|
||||
nsCOMPtr<nsIAtom> mLocaleLanguage;
|
||||
nsTArray<nsFontMetrics*> mFontMetrics;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsFontCache, nsIObserver)
|
||||
|
||||
// The Init and Destroy methods are necessary because it's not
|
||||
// safe to call AddObserver from a constructor or RemoveObserver
|
||||
// from a destructor. That should be fixed.
|
||||
void
|
||||
nsFontCache::Init(nsDeviceContext* aContext)
|
||||
{
|
||||
mContext = aContext;
|
||||
// register as a memory-pressure observer to free font resources
|
||||
// in low-memory situations.
|
||||
nsCOMPtr<nsIObserverService> obs = GetObserverService();
|
||||
if (obs)
|
||||
obs->AddObserver(this, "memory-pressure", false);
|
||||
|
||||
nsCOMPtr<nsILanguageAtomService> langService;
|
||||
langService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
|
||||
if (langService) {
|
||||
mLocaleLanguage = langService->GetLocaleLanguage();
|
||||
}
|
||||
if (!mLocaleLanguage) {
|
||||
mLocaleLanguage = NS_Atomize("x-western");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsFontCache::Destroy()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = GetObserverService();
|
||||
if (obs)
|
||||
obs->RemoveObserver(this, "memory-pressure");
|
||||
Flush();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFontCache::Observe(nsISupports*, const char* aTopic, const char16_t*)
|
||||
{
|
||||
if (!nsCRT::strcmp(aTopic, "memory-pressure"))
|
||||
Compact();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<nsFontMetrics>
|
||||
nsFontCache::GetMetricsFor(const nsFont& aFont,
|
||||
const nsFontMetrics::Params& aParams)
|
||||
{
|
||||
nsIAtom* language = aParams.language ? aParams.language
|
||||
: mLocaleLanguage.get();
|
||||
|
||||
// First check our cache
|
||||
// start from the end, which is where we put the most-recent-used element
|
||||
|
||||
int32_t n = mFontMetrics.Length() - 1;
|
||||
for (int32_t i = n; i >= 0; --i) {
|
||||
nsFontMetrics* fm = mFontMetrics[i];
|
||||
if (fm->Font().Equals(aFont) &&
|
||||
fm->GetUserFontSet() == aParams.userFontSet &&
|
||||
fm->Language() == language &&
|
||||
fm->Orientation() == aParams.orientation) {
|
||||
if (i != n) {
|
||||
// promote it to the end of the cache
|
||||
mFontMetrics.RemoveElementAt(i);
|
||||
mFontMetrics.AppendElement(fm);
|
||||
}
|
||||
fm->GetThebesFontGroup()->UpdateUserFonts();
|
||||
return do_AddRef(fm);
|
||||
}
|
||||
}
|
||||
|
||||
// It's not in the cache. Get font metrics and then cache them.
|
||||
|
||||
nsFontMetrics::Params params = aParams;
|
||||
params.language = language;
|
||||
RefPtr<nsFontMetrics> fm = new nsFontMetrics(aFont, params, mContext);
|
||||
// the mFontMetrics list has the "head" at the end, because append
|
||||
// is cheaper than insert
|
||||
mFontMetrics.AppendElement(do_AddRef(fm.get()).take());
|
||||
return fm.forget();
|
||||
}
|
||||
|
||||
void
|
||||
nsFontCache::FontMetricsDeleted(const nsFontMetrics* aFontMetrics)
|
||||
{
|
||||
mFontMetrics.RemoveElement(aFontMetrics);
|
||||
}
|
||||
|
||||
void
|
||||
nsFontCache::Compact()
|
||||
{
|
||||
// Need to loop backward because the running element can be removed on
|
||||
// the way
|
||||
for (int32_t i = mFontMetrics.Length()-1; i >= 0; --i) {
|
||||
nsFontMetrics* fm = mFontMetrics[i];
|
||||
nsFontMetrics* oldfm = fm;
|
||||
// Destroy() isn't here because we want our device context to be
|
||||
// notified
|
||||
NS_RELEASE(fm); // this will reset fm to nullptr
|
||||
// if the font is really gone, it would have called back in
|
||||
// FontMetricsDeleted() and would have removed itself
|
||||
if (mFontMetrics.IndexOf(oldfm) != mFontMetrics.NoIndex) {
|
||||
// nope, the font is still there, so let's hold onto it too
|
||||
NS_ADDREF(oldfm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsFontCache::Flush()
|
||||
{
|
||||
for (int32_t i = mFontMetrics.Length()-1; i >= 0; --i) {
|
||||
nsFontMetrics* fm = mFontMetrics[i];
|
||||
// Destroy() will unhook our device context from the fm so that we
|
||||
// won't waste time in triggering the notification of
|
||||
// FontMetricsDeleted() in the subsequent release
|
||||
fm->Destroy();
|
||||
NS_RELEASE(fm);
|
||||
}
|
||||
mFontMetrics.Clear();
|
||||
}
|
||||
|
||||
nsDeviceContext::nsDeviceContext()
|
||||
: mWidth(0), mHeight(0), mDepth(0),
|
||||
mAppUnitsPerDevPixel(-1), mAppUnitsPerDevPixelAtUnitFullZoom(-1),
|
||||
mAppUnitsPerPhysicalInch(-1),
|
||||
mFullZoom(1.0f), mPrintingScale(1.0f)
|
||||
#ifdef DEBUG
|
||||
, mIsInitialized(false)
|
||||
#endif
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "nsDeviceContext created off main thread");
|
||||
}
|
||||
|
||||
nsDeviceContext::~nsDeviceContext()
|
||||
{
|
||||
if (mFontCache) {
|
||||
mFontCache->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<nsFontMetrics>
|
||||
nsDeviceContext::GetMetricsFor(const nsFont& aFont,
|
||||
const nsFontMetrics::Params& aParams)
|
||||
{
|
||||
if (!mFontCache) {
|
||||
mFontCache = new nsFontCache();
|
||||
mFontCache->Init(this);
|
||||
}
|
||||
|
||||
return mFontCache->GetMetricsFor(aFont, aParams);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDeviceContext::FlushFontCache(void)
|
||||
{
|
||||
if (mFontCache)
|
||||
mFontCache->Flush();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDeviceContext::FontMetricsDeleted(const nsFontMetrics* aFontMetrics)
|
||||
{
|
||||
if (mFontCache) {
|
||||
mFontCache->FontMetricsDeleted(aFontMetrics);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDeviceContext::IsPrinterContext()
|
||||
{
|
||||
return mPrintTarget != nullptr
|
||||
#ifdef XP_MACOSX
|
||||
|| mCachedPrintTarget != nullptr
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
void
|
||||
nsDeviceContext::SetDPI(double* aScale)
|
||||
{
|
||||
float dpi = -1.0f;
|
||||
|
||||
// Use the printing DC to determine DPI values, if we have one.
|
||||
if (mDeviceContextSpec) {
|
||||
dpi = mDeviceContextSpec->GetDPI();
|
||||
mPrintingScale = mDeviceContextSpec->GetPrintingScale();
|
||||
mAppUnitsPerDevPixelAtUnitFullZoom =
|
||||
NS_lround((AppUnitsPerCSSPixel() * 96) / dpi);
|
||||
} else {
|
||||
// A value of -1 means use the maximum of 96 and the system DPI.
|
||||
// A value of 0 means use the system DPI. A positive value is used as the DPI.
|
||||
// This sets the physical size of a device pixel and thus controls the
|
||||
// interpretation of physical units.
|
||||
int32_t prefDPI = Preferences::GetInt("layout.css.dpi", -1);
|
||||
|
||||
if (prefDPI > 0) {
|
||||
dpi = prefDPI;
|
||||
} else if (mWidget) {
|
||||
dpi = mWidget->GetDPI();
|
||||
|
||||
if (prefDPI < 0) {
|
||||
dpi = std::max(96.0f, dpi);
|
||||
}
|
||||
} else {
|
||||
dpi = 96.0f;
|
||||
}
|
||||
|
||||
double devPixelsPerCSSPixel;
|
||||
if (aScale && *aScale > 0.0) {
|
||||
// if caller provided a scale, we just use it
|
||||
devPixelsPerCSSPixel = *aScale;
|
||||
} else {
|
||||
// otherwise get from the widget, and return it in aScale for
|
||||
// the caller to pass to child contexts if needed
|
||||
CSSToLayoutDeviceScale scale =
|
||||
mWidget ? mWidget->GetDefaultScale()
|
||||
: CSSToLayoutDeviceScale(1.0);
|
||||
devPixelsPerCSSPixel = scale.scale;
|
||||
if (aScale) {
|
||||
*aScale = devPixelsPerCSSPixel;
|
||||
}
|
||||
}
|
||||
|
||||
mAppUnitsPerDevPixelAtUnitFullZoom =
|
||||
std::max(1, NS_lround(AppUnitsPerCSSPixel() / devPixelsPerCSSPixel));
|
||||
}
|
||||
|
||||
NS_ASSERTION(dpi != -1.0, "no dpi set");
|
||||
|
||||
mAppUnitsPerPhysicalInch = NS_lround(dpi * mAppUnitsPerDevPixelAtUnitFullZoom);
|
||||
UpdateAppUnitsForFullZoom();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDeviceContext::Init(nsIWidget *aWidget)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
// We can't assert |!mIsInitialized| here since EndSwapDocShellsForDocument
|
||||
// re-initializes nsDeviceContext objects. We can only assert in
|
||||
// InitForPrinting (below).
|
||||
mIsInitialized = true;
|
||||
#endif
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (mScreenManager && mWidget == aWidget)
|
||||
return rv;
|
||||
|
||||
mWidget = aWidget;
|
||||
SetDPI();
|
||||
|
||||
if (mScreenManager)
|
||||
return rv;
|
||||
|
||||
mScreenManager = do_GetService("@mozilla.org/gfx/screenmanager;1", &rv);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// XXX This is only for printing. We should make that obvious in the name.
|
||||
already_AddRefed<gfxContext>
|
||||
nsDeviceContext::CreateRenderingContext()
|
||||
{
|
||||
return CreateRenderingContextCommon(/* not a reference context */ false);
|
||||
}
|
||||
|
||||
already_AddRefed<gfxContext>
|
||||
nsDeviceContext::CreateReferenceRenderingContext()
|
||||
{
|
||||
return CreateRenderingContextCommon(/* a reference context */ true);
|
||||
}
|
||||
|
||||
already_AddRefed<gfxContext>
|
||||
nsDeviceContext::CreateRenderingContextCommon(bool aWantReferenceContext)
|
||||
{
|
||||
MOZ_ASSERT(IsPrinterContext());
|
||||
MOZ_ASSERT(mWidth > 0 && mHeight > 0);
|
||||
|
||||
RefPtr<PrintTarget> printingTarget = mPrintTarget;
|
||||
#ifdef XP_MACOSX
|
||||
// CreateRenderingContext() can be called (on reflow) after EndPage()
|
||||
// but before BeginPage(). On OS X (and only there) mPrintTarget
|
||||
// will in this case be null, because OS X printing surfaces are
|
||||
// per-page, and therefore only truly valid between calls to BeginPage()
|
||||
// and EndPage(). But we can get away with fudging things here, if need
|
||||
// be, by using a cached copy.
|
||||
if (!printingTarget) {
|
||||
printingTarget = mCachedPrintTarget;
|
||||
}
|
||||
#endif
|
||||
|
||||
// This will usually be null, depending on the pref print.print_via_parent.
|
||||
RefPtr<DrawEventRecorder> recorder;
|
||||
mDeviceContextSpec->GetDrawEventRecorder(getter_AddRefs(recorder));
|
||||
|
||||
RefPtr<gfx::DrawTarget> dt;
|
||||
if (aWantReferenceContext) {
|
||||
dt = printingTarget->GetReferenceDrawTarget(recorder);
|
||||
} else {
|
||||
dt = printingTarget->MakeDrawTarget(gfx::IntSize(mWidth, mHeight), recorder);
|
||||
}
|
||||
|
||||
if (!dt || !dt->IsValid()) {
|
||||
gfxCriticalNote
|
||||
<< "Failed to create draw target in device context sized "
|
||||
<< mWidth << "x" << mHeight << " and pointers "
|
||||
<< hexa(mPrintTarget) << " and " << hexa(printingTarget);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
dt->AddUserData(&gfxContext::sDontUseAsSourceKey, dt, nullptr);
|
||||
#endif
|
||||
dt->AddUserData(&sDisablePixelSnapping, (void*)0x1, nullptr);
|
||||
|
||||
RefPtr<gfxContext> pContext = gfxContext::CreateOrNull(dt);
|
||||
MOZ_ASSERT(pContext); // already checked draw target above
|
||||
|
||||
gfxMatrix transform;
|
||||
if (printingTarget->RotateNeededForLandscape()) {
|
||||
// Rotate page 90 degrees to draw landscape page on portrait paper
|
||||
IntSize size = printingTarget->GetSize();
|
||||
transform.Translate(gfxPoint(0, size.width));
|
||||
gfxMatrix rotate(0, -1,
|
||||
1, 0,
|
||||
0, 0);
|
||||
transform = rotate * transform;
|
||||
}
|
||||
transform.Scale(mPrintingScale, mPrintingScale);
|
||||
|
||||
pContext->SetMatrix(transform);
|
||||
return pContext.forget();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDeviceContext::GetDepth(uint32_t& aDepth)
|
||||
{
|
||||
if (mDepth == 0 && mScreenManager) {
|
||||
nsCOMPtr<nsIScreen> primaryScreen;
|
||||
mScreenManager->GetPrimaryScreen(getter_AddRefs(primaryScreen));
|
||||
primaryScreen->GetColorDepth(reinterpret_cast<int32_t *>(&mDepth));
|
||||
}
|
||||
|
||||
aDepth = mDepth;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDeviceContext::GetDeviceSurfaceDimensions(nscoord &aWidth, nscoord &aHeight)
|
||||
{
|
||||
if (IsPrinterContext()) {
|
||||
aWidth = mWidth;
|
||||
aHeight = mHeight;
|
||||
} else {
|
||||
nsRect area;
|
||||
ComputeFullAreaUsingScreen(&area);
|
||||
aWidth = area.width;
|
||||
aHeight = area.height;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDeviceContext::GetRect(nsRect &aRect)
|
||||
{
|
||||
if (IsPrinterContext()) {
|
||||
aRect.x = 0;
|
||||
aRect.y = 0;
|
||||
aRect.width = mWidth;
|
||||
aRect.height = mHeight;
|
||||
} else
|
||||
ComputeFullAreaUsingScreen ( &aRect );
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDeviceContext::GetClientRect(nsRect &aRect)
|
||||
{
|
||||
if (IsPrinterContext()) {
|
||||
aRect.x = 0;
|
||||
aRect.y = 0;
|
||||
aRect.width = mWidth;
|
||||
aRect.height = mHeight;
|
||||
}
|
||||
else
|
||||
ComputeClientRectUsingScreen(&aRect);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDeviceContext::InitForPrinting(nsIDeviceContextSpec *aDevice)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aDevice);
|
||||
|
||||
MOZ_ASSERT(!mIsInitialized,
|
||||
"Only initialize once, immediately after construction");
|
||||
|
||||
// We don't set mIsInitialized here. The Init() call below does that.
|
||||
|
||||
mPrintTarget = aDevice->MakePrintTarget();
|
||||
if (!mPrintTarget) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mDeviceContextSpec = aDevice;
|
||||
|
||||
Init(nullptr);
|
||||
|
||||
if (!CalcPrintingSize()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDeviceContext::BeginDocument(const nsAString& aTitle,
|
||||
const nsAString& aPrintToFileName,
|
||||
int32_t aStartPage,
|
||||
int32_t aEndPage)
|
||||
{
|
||||
nsresult rv = mPrintTarget->BeginPrinting(aTitle, aPrintToFileName);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && mDeviceContextSpec) {
|
||||
rv = mDeviceContextSpec->BeginDocument(aTitle, aPrintToFileName,
|
||||
aStartPage, aEndPage);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDeviceContext::EndDocument(void)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (mPrintTarget) {
|
||||
rv = mPrintTarget->EndPrinting();
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mPrintTarget->Finish();
|
||||
}
|
||||
|
||||
if (mDeviceContextSpec)
|
||||
mDeviceContextSpec->EndDocument();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDeviceContext::AbortDocument(void)
|
||||
{
|
||||
nsresult rv = mPrintTarget->AbortPrinting();
|
||||
|
||||
if (mDeviceContextSpec)
|
||||
mDeviceContextSpec->EndDocument();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDeviceContext::BeginPage(void)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (mDeviceContextSpec)
|
||||
rv = mDeviceContextSpec->BeginPage();
|
||||
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// We need to get a new surface for each page on the Mac, as the
|
||||
// CGContextRefs are only good for one page.
|
||||
mPrintTarget = mDeviceContextSpec->MakePrintTarget();
|
||||
#endif
|
||||
|
||||
rv = mPrintTarget->BeginPage();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDeviceContext::EndPage(void)
|
||||
{
|
||||
nsresult rv = mPrintTarget->EndPage();
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// We need to release the CGContextRef in the surface here, plus it's
|
||||
// not something you would want anyway, as these CGContextRefs are only
|
||||
// good for one page. But we need to keep a cached reference to it, since
|
||||
// CreateRenderingContext() may try to access it when mPrintTarget
|
||||
// would normally be null. See bug 665218. If we just stop nulling out
|
||||
// mPrintTarget here (and thereby make that our cached copy), we'll
|
||||
// break all our null checks on mPrintTarget. See bug 684622.
|
||||
mCachedPrintTarget = mPrintTarget;
|
||||
mPrintTarget = nullptr;
|
||||
#endif
|
||||
|
||||
if (mDeviceContextSpec)
|
||||
mDeviceContextSpec->EndPage();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
nsDeviceContext::ComputeClientRectUsingScreen(nsRect* outRect)
|
||||
{
|
||||
// we always need to recompute the clientRect
|
||||
// because the window may have moved onto a different screen. In the single
|
||||
// monitor case, we only need to do the computation if we haven't done it
|
||||
// once already, and remember that we have because we're assured it won't change.
|
||||
nsCOMPtr<nsIScreen> screen;
|
||||
FindScreen (getter_AddRefs(screen));
|
||||
if (screen) {
|
||||
int32_t x, y, width, height;
|
||||
screen->GetAvailRect(&x, &y, &width, &height);
|
||||
|
||||
// convert to device units
|
||||
outRect->y = NSIntPixelsToAppUnits(y, AppUnitsPerDevPixel());
|
||||
outRect->x = NSIntPixelsToAppUnits(x, AppUnitsPerDevPixel());
|
||||
outRect->width = NSIntPixelsToAppUnits(width, AppUnitsPerDevPixel());
|
||||
outRect->height = NSIntPixelsToAppUnits(height, AppUnitsPerDevPixel());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDeviceContext::ComputeFullAreaUsingScreen(nsRect* outRect)
|
||||
{
|
||||
// if we have more than one screen, we always need to recompute the clientRect
|
||||
// because the window may have moved onto a different screen. In the single
|
||||
// monitor case, we only need to do the computation if we haven't done it
|
||||
// once already, and remember that we have because we're assured it won't change.
|
||||
nsCOMPtr<nsIScreen> screen;
|
||||
FindScreen ( getter_AddRefs(screen) );
|
||||
if ( screen ) {
|
||||
int32_t x, y, width, height;
|
||||
screen->GetRect ( &x, &y, &width, &height );
|
||||
|
||||
// convert to device units
|
||||
outRect->y = NSIntPixelsToAppUnits(y, AppUnitsPerDevPixel());
|
||||
outRect->x = NSIntPixelsToAppUnits(x, AppUnitsPerDevPixel());
|
||||
outRect->width = NSIntPixelsToAppUnits(width, AppUnitsPerDevPixel());
|
||||
outRect->height = NSIntPixelsToAppUnits(height, AppUnitsPerDevPixel());
|
||||
|
||||
mWidth = outRect->width;
|
||||
mHeight = outRect->height;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// FindScreen
|
||||
//
|
||||
// Determines which screen intersects the largest area of the given surface.
|
||||
//
|
||||
void
|
||||
nsDeviceContext::FindScreen(nsIScreen** outScreen)
|
||||
{
|
||||
if (!mWidget || !mScreenManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
CheckDPIChange();
|
||||
|
||||
if (mWidget->GetOwningTabChild()) {
|
||||
mScreenManager->ScreenForNativeWidget((void *)mWidget->GetOwningTabChild(),
|
||||
outScreen);
|
||||
}
|
||||
else if (mWidget->GetNativeData(NS_NATIVE_WINDOW)) {
|
||||
mScreenManager->ScreenForNativeWidget(mWidget->GetNativeData(NS_NATIVE_WINDOW),
|
||||
outScreen);
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
if (!(*outScreen)) {
|
||||
nsCOMPtr<nsIScreen> screen = mWidget->GetWidgetScreen();
|
||||
screen.forget(outScreen);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(*outScreen)) {
|
||||
mScreenManager->GetPrimaryScreen(outScreen);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsDeviceContext::CalcPrintingSize()
|
||||
{
|
||||
if (!mPrintTarget) {
|
||||
return (mWidth > 0 && mHeight > 0);
|
||||
}
|
||||
|
||||
gfxSize size = mPrintTarget->GetSize();
|
||||
// For printing, CSS inches and physical inches are identical
|
||||
// so it doesn't matter which we use here
|
||||
mWidth = NSToCoordRound(size.width * AppUnitsPerPhysicalInch()
|
||||
/ POINTS_PER_INCH_FLOAT);
|
||||
mHeight = NSToCoordRound(size.height * AppUnitsPerPhysicalInch()
|
||||
/ POINTS_PER_INCH_FLOAT);
|
||||
|
||||
return (mWidth > 0 && mHeight > 0);
|
||||
}
|
||||
|
||||
bool nsDeviceContext::CheckDPIChange(double* aScale)
|
||||
{
|
||||
int32_t oldDevPixels = mAppUnitsPerDevPixelAtUnitFullZoom;
|
||||
int32_t oldInches = mAppUnitsPerPhysicalInch;
|
||||
|
||||
SetDPI(aScale);
|
||||
|
||||
return oldDevPixels != mAppUnitsPerDevPixelAtUnitFullZoom ||
|
||||
oldInches != mAppUnitsPerPhysicalInch;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDeviceContext::SetFullZoom(float aScale)
|
||||
{
|
||||
if (aScale <= 0) {
|
||||
NS_NOTREACHED("Invalid full zoom value");
|
||||
return false;
|
||||
}
|
||||
int32_t oldAppUnitsPerDevPixel = mAppUnitsPerDevPixel;
|
||||
mFullZoom = aScale;
|
||||
UpdateAppUnitsForFullZoom();
|
||||
return oldAppUnitsPerDevPixel != mAppUnitsPerDevPixel;
|
||||
}
|
||||
|
||||
void
|
||||
nsDeviceContext::UpdateAppUnitsForFullZoom()
|
||||
{
|
||||
mAppUnitsPerDevPixel =
|
||||
std::max(1, NSToIntRound(float(mAppUnitsPerDevPixelAtUnitFullZoom) / mFullZoom));
|
||||
// adjust mFullZoom to reflect appunit rounding
|
||||
mFullZoom = float(mAppUnitsPerDevPixelAtUnitFullZoom) / mAppUnitsPerDevPixel;
|
||||
}
|
||||
|
||||
DesktopToLayoutDeviceScale
|
||||
nsDeviceContext::GetDesktopToDeviceScale()
|
||||
{
|
||||
nsCOMPtr<nsIScreen> screen;
|
||||
FindScreen(getter_AddRefs(screen));
|
||||
|
||||
if (screen) {
|
||||
double scale;
|
||||
screen->GetContentsScaleFactor(&scale);
|
||||
return DesktopToLayoutDeviceScale(scale);
|
||||
}
|
||||
|
||||
return DesktopToLayoutDeviceScale(1.0);
|
||||
}
|
||||
311
gfx/src/nsDeviceContext.h
Normal file
311
gfx/src/nsDeviceContext.h
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
/* -*- Mode: C++; 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 _NS_DEVICECONTEXT_H_
|
||||
#define _NS_DEVICECONTEXT_H_
|
||||
|
||||
#include <stdint.h> // for uint32_t
|
||||
#include <sys/types.h> // for int32_t
|
||||
#include "gfxTypes.h" // for gfxFloat
|
||||
#include "gfxFont.h" // for gfxFont::Orientation
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
|
||||
#include "mozilla/RefPtr.h" // for RefPtr
|
||||
#include "nsCOMPtr.h" // for nsCOMPtr
|
||||
#include "nsCoord.h" // for nscoord
|
||||
#include "nsError.h" // for nsresult
|
||||
#include "nsISupports.h" // for NS_INLINE_DECL_REFCOUNTING
|
||||
#include "nsMathUtils.h" // for NS_round
|
||||
#include "nscore.h" // for char16_t, nsAString
|
||||
#include "mozilla/AppUnits.h" // for AppUnits
|
||||
#include "nsFontMetrics.h" // for nsFontMetrics::Params
|
||||
|
||||
class gfxContext;
|
||||
class gfxTextPerfMetrics;
|
||||
class gfxUserFontSet;
|
||||
struct nsFont;
|
||||
class nsFontCache;
|
||||
class nsIAtom;
|
||||
class nsIDeviceContextSpec;
|
||||
class nsIScreen;
|
||||
class nsIScreenManager;
|
||||
class nsIWidget;
|
||||
struct nsRect;
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
class PrintTarget;
|
||||
}
|
||||
}
|
||||
|
||||
class nsDeviceContext final
|
||||
{
|
||||
public:
|
||||
typedef mozilla::gfx::PrintTarget PrintTarget;
|
||||
|
||||
nsDeviceContext();
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(nsDeviceContext)
|
||||
|
||||
/**
|
||||
* Initialize the device context from a widget
|
||||
* @param aWidget a widget to initialize the device context from
|
||||
* @return error status
|
||||
*/
|
||||
nsresult Init(nsIWidget *aWidget);
|
||||
|
||||
/**
|
||||
* Initialize the device context from a device context spec
|
||||
* @param aDevSpec the specification of the printing device
|
||||
* @return error status
|
||||
*/
|
||||
nsresult InitForPrinting(nsIDeviceContextSpec *aDevSpec);
|
||||
|
||||
/**
|
||||
* Create a rendering context and initialize it. Only call this
|
||||
* method on device contexts that were initialized for printing.
|
||||
*
|
||||
* @return the new rendering context (guaranteed to be non-null)
|
||||
*/
|
||||
already_AddRefed<gfxContext> CreateRenderingContext();
|
||||
|
||||
/**
|
||||
* Create a reference rendering context and initialize it. Only call this
|
||||
* method on device contexts that were initialized for printing.
|
||||
*
|
||||
* @return the new rendering context.
|
||||
*/
|
||||
already_AddRefed<gfxContext> CreateReferenceRenderingContext();
|
||||
|
||||
/**
|
||||
* Gets the number of app units in one CSS pixel; this number is global,
|
||||
* not unique to each device context.
|
||||
*/
|
||||
static int32_t AppUnitsPerCSSPixel() { return mozilla::AppUnitsPerCSSPixel(); }
|
||||
|
||||
/**
|
||||
* Gets the number of app units in one device pixel; this number
|
||||
* is usually a factor of AppUnitsPerCSSPixel(), although that is
|
||||
* not guaranteed.
|
||||
*/
|
||||
int32_t AppUnitsPerDevPixel() const { return mAppUnitsPerDevPixel; }
|
||||
|
||||
/**
|
||||
* Convert device pixels which is used for gfx/thebes to nearest
|
||||
* (rounded) app units
|
||||
*/
|
||||
nscoord GfxUnitsToAppUnits(gfxFloat aGfxUnits) const
|
||||
{ return nscoord(NS_round(aGfxUnits * AppUnitsPerDevPixel())); }
|
||||
|
||||
/**
|
||||
* Convert app units to device pixels which is used for gfx/thebes.
|
||||
*/
|
||||
gfxFloat AppUnitsToGfxUnits(nscoord aAppUnits) const
|
||||
{ return gfxFloat(aAppUnits) / AppUnitsPerDevPixel(); }
|
||||
|
||||
/**
|
||||
* Gets the number of app units in one physical inch; this is the
|
||||
* device's DPI times AppUnitsPerDevPixel().
|
||||
*/
|
||||
int32_t AppUnitsPerPhysicalInch() const
|
||||
{ return mAppUnitsPerPhysicalInch; }
|
||||
|
||||
/**
|
||||
* Gets the number of app units in one CSS inch; this is
|
||||
* 96 times AppUnitsPerCSSPixel.
|
||||
*/
|
||||
static int32_t AppUnitsPerCSSInch() { return mozilla::AppUnitsPerCSSInch(); }
|
||||
|
||||
/**
|
||||
* Get the ratio of app units to dev pixels that would be used at unit
|
||||
* (100%) full zoom.
|
||||
*/
|
||||
int32_t AppUnitsPerDevPixelAtUnitFullZoom() const
|
||||
{ return mAppUnitsPerDevPixelAtUnitFullZoom; }
|
||||
|
||||
/**
|
||||
* Get the nsFontMetrics that describe the properties of
|
||||
* an nsFont.
|
||||
* @param aFont font description to obtain metrics for
|
||||
*/
|
||||
already_AddRefed<nsFontMetrics> GetMetricsFor(
|
||||
const nsFont& aFont, const nsFontMetrics::Params& aParams);
|
||||
|
||||
/**
|
||||
* Notification when a font metrics instance created for this device is
|
||||
* about to be deleted
|
||||
*/
|
||||
nsresult FontMetricsDeleted(const nsFontMetrics* aFontMetrics);
|
||||
|
||||
/**
|
||||
* Attempt to free up resources by flushing out any fonts no longer
|
||||
* referenced by anything other than the font cache itself.
|
||||
* @return error status
|
||||
*/
|
||||
nsresult FlushFontCache();
|
||||
|
||||
/**
|
||||
* Return the bit depth of the device.
|
||||
*/
|
||||
nsresult GetDepth(uint32_t& aDepth);
|
||||
|
||||
/**
|
||||
* Get the size of the displayable area of the output device
|
||||
* in app units.
|
||||
* @param aWidth out parameter for width
|
||||
* @param aHeight out parameter for height
|
||||
* @return error status
|
||||
*/
|
||||
nsresult GetDeviceSurfaceDimensions(nscoord& aWidth, nscoord& aHeight);
|
||||
|
||||
/**
|
||||
* Get the size of the content area of the output device in app
|
||||
* units. This corresponds on a screen device, for instance, to
|
||||
* the entire screen.
|
||||
* @param aRect out parameter for full rect. Position (x,y) will
|
||||
* be (0,0) or relative to the primary monitor if
|
||||
* this is not the primary.
|
||||
* @return error status
|
||||
*/
|
||||
nsresult GetRect(nsRect& aRect);
|
||||
|
||||
/**
|
||||
* Get the size of the content area of the output device in app
|
||||
* units. This corresponds on a screen device, for instance, to
|
||||
* the area reported by GetDeviceSurfaceDimensions, minus the
|
||||
* taskbar (Windows) or menubar (Macintosh).
|
||||
* @param aRect out parameter for client rect. Position (x,y) will
|
||||
* be (0,0) adjusted for any upper/left non-client
|
||||
* space if present or relative to the primary
|
||||
* monitor if this is not the primary.
|
||||
* @return error status
|
||||
*/
|
||||
nsresult GetClientRect(nsRect& aRect);
|
||||
|
||||
/**
|
||||
* Inform the output device that output of a document is beginning
|
||||
* Used for print related device contexts. Must be matched 1:1 with
|
||||
* EndDocument() or AbortDocument().
|
||||
*
|
||||
* @param aTitle - title of Document
|
||||
* @param aPrintToFileName - name of file to print to, if empty then don't
|
||||
* print to file
|
||||
* @param aStartPage - starting page number (must be greater than zero)
|
||||
* @param aEndPage - ending page number (must be less than or
|
||||
* equal to number of pages)
|
||||
*
|
||||
* @return error status
|
||||
*/
|
||||
nsresult BeginDocument(const nsAString& aTitle,
|
||||
const nsAString& aPrintToFileName,
|
||||
int32_t aStartPage,
|
||||
int32_t aEndPage);
|
||||
|
||||
/**
|
||||
* Inform the output device that output of a document is ending.
|
||||
* Used for print related device contexts. Must be matched 1:1 with
|
||||
* BeginDocument()
|
||||
* @return error status
|
||||
*/
|
||||
nsresult EndDocument();
|
||||
|
||||
/**
|
||||
* Inform the output device that output of a document is being aborted.
|
||||
* Must be matched 1:1 with BeginDocument()
|
||||
* @return error status
|
||||
*/
|
||||
nsresult AbortDocument();
|
||||
|
||||
/**
|
||||
* Inform the output device that output of a page is beginning
|
||||
* Used for print related device contexts. Must be matched 1:1 with
|
||||
* EndPage() and within a BeginDocument()/EndDocument() pair.
|
||||
* @return error status
|
||||
*/
|
||||
nsresult BeginPage();
|
||||
|
||||
/**
|
||||
* Inform the output device that output of a page is ending
|
||||
* Used for print related device contexts. Must be matched 1:1 with
|
||||
* BeginPage() and within a BeginDocument()/EndDocument() pair.
|
||||
* @return error status
|
||||
*/
|
||||
nsresult EndPage();
|
||||
|
||||
/**
|
||||
* Check to see if the DPI has changed, or impose a new DPI scale value.
|
||||
* @param aScale - If non-null, the default (unzoomed) CSS to device pixel
|
||||
* scale factor will be returned here; and if it is > 0.0
|
||||
* on input, the given value will be used instead of
|
||||
* getting it from the widget (if any). This is used to
|
||||
* allow subdocument contexts to inherit the resolution
|
||||
* setting of their parent.
|
||||
* @return whether there was actually a change in the DPI (whether
|
||||
* AppUnitsPerDevPixel() or AppUnitsPerPhysicalInch()
|
||||
* changed)
|
||||
*/
|
||||
bool CheckDPIChange(double* aScale = nullptr);
|
||||
|
||||
/**
|
||||
* Set the full zoom factor: all lengths are multiplied by this factor
|
||||
* when we convert them to device pixels. Returns whether the ratio of
|
||||
* app units to dev pixels changed because of the zoom factor.
|
||||
*/
|
||||
bool SetFullZoom(float aScale);
|
||||
|
||||
/**
|
||||
* Returns the page full zoom factor applied.
|
||||
*/
|
||||
float GetFullZoom() const { return mFullZoom; }
|
||||
|
||||
/**
|
||||
* True if this device context was created for printing.
|
||||
*/
|
||||
bool IsPrinterContext();
|
||||
|
||||
mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale();
|
||||
|
||||
private:
|
||||
// Private destructor, to discourage deletion outside of Release():
|
||||
~nsDeviceContext();
|
||||
|
||||
/**
|
||||
* Implementation shared by CreateRenderingContext and
|
||||
* CreateReferenceRenderingContext.
|
||||
*/
|
||||
already_AddRefed<gfxContext>
|
||||
CreateRenderingContextCommon(bool aWantReferenceContext);
|
||||
|
||||
void SetDPI(double* aScale = nullptr);
|
||||
void ComputeClientRectUsingScreen(nsRect *outRect);
|
||||
void ComputeFullAreaUsingScreen(nsRect *outRect);
|
||||
void FindScreen(nsIScreen **outScreen);
|
||||
|
||||
// Return false if the surface is not right
|
||||
bool CalcPrintingSize();
|
||||
void UpdateAppUnitsForFullZoom();
|
||||
|
||||
nscoord mWidth;
|
||||
nscoord mHeight;
|
||||
uint32_t mDepth;
|
||||
int32_t mAppUnitsPerDevPixel;
|
||||
int32_t mAppUnitsPerDevPixelAtUnitFullZoom;
|
||||
int32_t mAppUnitsPerPhysicalInch;
|
||||
float mFullZoom;
|
||||
float mPrintingScale;
|
||||
|
||||
RefPtr<nsFontCache> mFontCache;
|
||||
nsCOMPtr<nsIWidget> mWidget;
|
||||
nsCOMPtr<nsIScreenManager> mScreenManager;
|
||||
nsCOMPtr<nsIDeviceContextSpec> mDeviceContextSpec;
|
||||
RefPtr<PrintTarget> mPrintTarget;
|
||||
#ifdef XP_MACOSX
|
||||
RefPtr<PrintTarget> mCachedPrintTarget;
|
||||
#endif
|
||||
#ifdef DEBUG
|
||||
bool mIsInitialized;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* _NS_DEVICECONTEXT_H_ */
|
||||
297
gfx/src/nsFont.cpp
Normal file
297
gfx/src/nsFont.cpp
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
/* -*- 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 "nsFont.h"
|
||||
#include "gfxFont.h" // for gfxFontStyle
|
||||
#include "gfxFontConstants.h" // for NS_FONT_KERNING_AUTO, etc
|
||||
#include "gfxFontFeatures.h" // for gfxFontFeature, etc
|
||||
#include "gfxFontUtils.h" // for TRUETYPE_TAG
|
||||
#include "nsCRT.h" // for nsCRT
|
||||
#include "nsDebug.h" // for NS_ASSERTION
|
||||
#include "nsISupports.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nscore.h" // for char16_t
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
nsFont::nsFont(const FontFamilyList& aFontlist, nscoord aSize)
|
||||
: fontlist(aFontlist)
|
||||
{
|
||||
Init();
|
||||
size = aSize;
|
||||
}
|
||||
|
||||
nsFont::nsFont(FontFamilyType aGenericType, nscoord aSize)
|
||||
: fontlist(aGenericType)
|
||||
{
|
||||
Init();
|
||||
size = aSize;
|
||||
}
|
||||
|
||||
void
|
||||
nsFont::Init()
|
||||
{
|
||||
style = NS_FONT_STYLE_NORMAL;
|
||||
weight = NS_FONT_WEIGHT_NORMAL;
|
||||
stretch = NS_FONT_STRETCH_NORMAL;
|
||||
systemFont = false;
|
||||
smoothing = NS_FONT_SMOOTHING_AUTO;
|
||||
sizeAdjust = -1.0f;
|
||||
kerning = NS_FONT_KERNING_AUTO;
|
||||
synthesis = NS_FONT_SYNTHESIS_WEIGHT | NS_FONT_SYNTHESIS_STYLE;
|
||||
|
||||
variantAlternates = 0;
|
||||
variantCaps = NS_FONT_VARIANT_CAPS_NORMAL;
|
||||
variantEastAsian = 0;
|
||||
variantLigatures = 0;
|
||||
variantNumeric = 0;
|
||||
variantPosition = NS_FONT_VARIANT_POSITION_NORMAL;
|
||||
variantWidth = NS_FONT_VARIANT_WIDTH_NORMAL;
|
||||
}
|
||||
|
||||
nsFont::nsFont(const nsFont& aOther) = default;
|
||||
|
||||
nsFont::nsFont()
|
||||
{
|
||||
}
|
||||
|
||||
nsFont::~nsFont()
|
||||
{
|
||||
}
|
||||
|
||||
bool nsFont::Equals(const nsFont& aOther) const
|
||||
{
|
||||
if ((style == aOther.style) &&
|
||||
(systemFont == aOther.systemFont) &&
|
||||
(weight == aOther.weight) &&
|
||||
(stretch == aOther.stretch) &&
|
||||
(size == aOther.size) &&
|
||||
(sizeAdjust == aOther.sizeAdjust) &&
|
||||
(fontlist == aOther.fontlist) &&
|
||||
(kerning == aOther.kerning) &&
|
||||
(synthesis == aOther.synthesis) &&
|
||||
(fontFeatureSettings == aOther.fontFeatureSettings) &&
|
||||
(languageOverride == aOther.languageOverride) &&
|
||||
(variantAlternates == aOther.variantAlternates) &&
|
||||
(variantCaps == aOther.variantCaps) &&
|
||||
(variantEastAsian == aOther.variantEastAsian) &&
|
||||
(variantLigatures == aOther.variantLigatures) &&
|
||||
(variantNumeric == aOther.variantNumeric) &&
|
||||
(variantPosition == aOther.variantPosition) &&
|
||||
(variantWidth == aOther.variantWidth) &&
|
||||
(alternateValues == aOther.alternateValues) &&
|
||||
(featureValueLookup == aOther.featureValueLookup) &&
|
||||
(smoothing == aOther.smoothing)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
nsFont& nsFont::operator=(const nsFont& aOther) = default;
|
||||
|
||||
void
|
||||
nsFont::CopyAlternates(const nsFont& aOther)
|
||||
{
|
||||
variantAlternates = aOther.variantAlternates;
|
||||
alternateValues = aOther.alternateValues;
|
||||
featureValueLookup = aOther.featureValueLookup;
|
||||
}
|
||||
|
||||
// mapping from bitflag to font feature tag/value pair
|
||||
//
|
||||
// these need to be kept in sync with the constants listed
|
||||
// in gfxFontConstants.h (e.g. NS_FONT_VARIANT_EAST_ASIAN_JIS78)
|
||||
|
||||
// NS_FONT_VARIANT_EAST_ASIAN_xxx values
|
||||
const gfxFontFeature eastAsianDefaults[] = {
|
||||
{ TRUETYPE_TAG('j','p','7','8'), 1 },
|
||||
{ TRUETYPE_TAG('j','p','8','3'), 1 },
|
||||
{ TRUETYPE_TAG('j','p','9','0'), 1 },
|
||||
{ TRUETYPE_TAG('j','p','0','4'), 1 },
|
||||
{ TRUETYPE_TAG('s','m','p','l'), 1 },
|
||||
{ TRUETYPE_TAG('t','r','a','d'), 1 },
|
||||
{ TRUETYPE_TAG('f','w','i','d'), 1 },
|
||||
{ TRUETYPE_TAG('p','w','i','d'), 1 },
|
||||
{ TRUETYPE_TAG('r','u','b','y'), 1 }
|
||||
};
|
||||
|
||||
static_assert(MOZ_ARRAY_LENGTH(eastAsianDefaults) ==
|
||||
eFeatureEastAsian_numFeatures,
|
||||
"eFeatureEastAsian_numFeatures should be correct");
|
||||
|
||||
// NS_FONT_VARIANT_LIGATURES_xxx values
|
||||
const gfxFontFeature ligDefaults[] = {
|
||||
{ TRUETYPE_TAG('l','i','g','a'), 0 }, // none value means all off
|
||||
{ TRUETYPE_TAG('l','i','g','a'), 1 },
|
||||
{ TRUETYPE_TAG('l','i','g','a'), 0 },
|
||||
{ TRUETYPE_TAG('d','l','i','g'), 1 },
|
||||
{ TRUETYPE_TAG('d','l','i','g'), 0 },
|
||||
{ TRUETYPE_TAG('h','l','i','g'), 1 },
|
||||
{ TRUETYPE_TAG('h','l','i','g'), 0 },
|
||||
{ TRUETYPE_TAG('c','a','l','t'), 1 },
|
||||
{ TRUETYPE_TAG('c','a','l','t'), 0 }
|
||||
};
|
||||
|
||||
static_assert(MOZ_ARRAY_LENGTH(ligDefaults) ==
|
||||
eFeatureLigatures_numFeatures,
|
||||
"eFeatureLigatures_numFeatures should be correct");
|
||||
|
||||
// NS_FONT_VARIANT_NUMERIC_xxx values
|
||||
const gfxFontFeature numericDefaults[] = {
|
||||
{ TRUETYPE_TAG('l','n','u','m'), 1 },
|
||||
{ TRUETYPE_TAG('o','n','u','m'), 1 },
|
||||
{ TRUETYPE_TAG('p','n','u','m'), 1 },
|
||||
{ TRUETYPE_TAG('t','n','u','m'), 1 },
|
||||
{ TRUETYPE_TAG('f','r','a','c'), 1 },
|
||||
{ TRUETYPE_TAG('a','f','r','c'), 1 },
|
||||
{ TRUETYPE_TAG('z','e','r','o'), 1 },
|
||||
{ TRUETYPE_TAG('o','r','d','n'), 1 }
|
||||
};
|
||||
|
||||
static_assert(MOZ_ARRAY_LENGTH(numericDefaults) ==
|
||||
eFeatureNumeric_numFeatures,
|
||||
"eFeatureNumeric_numFeatures should be correct");
|
||||
|
||||
static void
|
||||
AddFontFeaturesBitmask(uint32_t aValue, uint32_t aMin, uint32_t aMax,
|
||||
const gfxFontFeature aFeatureDefaults[],
|
||||
nsTArray<gfxFontFeature>& aFeaturesOut)
|
||||
|
||||
{
|
||||
uint32_t i, m;
|
||||
|
||||
for (i = 0, m = aMin; m <= aMax; i++, m <<= 1) {
|
||||
if (m & aValue) {
|
||||
const gfxFontFeature& feature = aFeatureDefaults[i];
|
||||
aFeaturesOut.AppendElement(feature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
FontFeatureTagForVariantWidth(uint32_t aVariantWidth)
|
||||
{
|
||||
switch (aVariantWidth) {
|
||||
case NS_FONT_VARIANT_WIDTH_FULL:
|
||||
return TRUETYPE_TAG('f','w','i','d');
|
||||
case NS_FONT_VARIANT_WIDTH_HALF:
|
||||
return TRUETYPE_TAG('h','w','i','d');
|
||||
case NS_FONT_VARIANT_WIDTH_THIRD:
|
||||
return TRUETYPE_TAG('t','w','i','d');
|
||||
case NS_FONT_VARIANT_WIDTH_QUARTER:
|
||||
return TRUETYPE_TAG('q','w','i','d');
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void nsFont::AddFontFeaturesToStyle(gfxFontStyle *aStyle) const
|
||||
{
|
||||
// add in font-variant features
|
||||
gfxFontFeature setting;
|
||||
|
||||
// -- kerning
|
||||
setting.mTag = TRUETYPE_TAG('k','e','r','n');
|
||||
switch (kerning) {
|
||||
case NS_FONT_KERNING_NONE:
|
||||
setting.mValue = 0;
|
||||
aStyle->featureSettings.AppendElement(setting);
|
||||
break;
|
||||
case NS_FONT_KERNING_NORMAL:
|
||||
setting.mValue = 1;
|
||||
aStyle->featureSettings.AppendElement(setting);
|
||||
break;
|
||||
default:
|
||||
// auto case implies use user agent default
|
||||
break;
|
||||
}
|
||||
|
||||
// -- alternates
|
||||
if (variantAlternates & NS_FONT_VARIANT_ALTERNATES_HISTORICAL) {
|
||||
setting.mValue = 1;
|
||||
setting.mTag = TRUETYPE_TAG('h','i','s','t');
|
||||
aStyle->featureSettings.AppendElement(setting);
|
||||
}
|
||||
|
||||
// -- copy font-specific alternate info into style
|
||||
// (this will be resolved after font-matching occurs)
|
||||
aStyle->alternateValues.AppendElements(alternateValues);
|
||||
aStyle->featureValueLookup = featureValueLookup;
|
||||
|
||||
// -- caps
|
||||
aStyle->variantCaps = variantCaps;
|
||||
|
||||
// -- east-asian
|
||||
if (variantEastAsian) {
|
||||
AddFontFeaturesBitmask(variantEastAsian,
|
||||
NS_FONT_VARIANT_EAST_ASIAN_JIS78,
|
||||
NS_FONT_VARIANT_EAST_ASIAN_RUBY,
|
||||
eastAsianDefaults, aStyle->featureSettings);
|
||||
}
|
||||
|
||||
// -- ligatures
|
||||
if (variantLigatures) {
|
||||
AddFontFeaturesBitmask(variantLigatures,
|
||||
NS_FONT_VARIANT_LIGATURES_NONE,
|
||||
NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL,
|
||||
ligDefaults, aStyle->featureSettings);
|
||||
|
||||
if (variantLigatures & NS_FONT_VARIANT_LIGATURES_COMMON) {
|
||||
// liga already enabled, need to enable clig also
|
||||
setting.mTag = TRUETYPE_TAG('c','l','i','g');
|
||||
setting.mValue = 1;
|
||||
aStyle->featureSettings.AppendElement(setting);
|
||||
} else if (variantLigatures & NS_FONT_VARIANT_LIGATURES_NO_COMMON) {
|
||||
// liga already disabled, need to disable clig also
|
||||
setting.mTag = TRUETYPE_TAG('c','l','i','g');
|
||||
setting.mValue = 0;
|
||||
aStyle->featureSettings.AppendElement(setting);
|
||||
} else if (variantLigatures & NS_FONT_VARIANT_LIGATURES_NONE) {
|
||||
// liga already disabled, need to disable dlig, hlig, calt, clig
|
||||
setting.mValue = 0;
|
||||
setting.mTag = TRUETYPE_TAG('d','l','i','g');
|
||||
aStyle->featureSettings.AppendElement(setting);
|
||||
setting.mTag = TRUETYPE_TAG('h','l','i','g');
|
||||
aStyle->featureSettings.AppendElement(setting);
|
||||
setting.mTag = TRUETYPE_TAG('c','a','l','t');
|
||||
aStyle->featureSettings.AppendElement(setting);
|
||||
setting.mTag = TRUETYPE_TAG('c','l','i','g');
|
||||
aStyle->featureSettings.AppendElement(setting);
|
||||
}
|
||||
}
|
||||
|
||||
// -- numeric
|
||||
if (variantNumeric) {
|
||||
AddFontFeaturesBitmask(variantNumeric,
|
||||
NS_FONT_VARIANT_NUMERIC_LINING,
|
||||
NS_FONT_VARIANT_NUMERIC_ORDINAL,
|
||||
numericDefaults, aStyle->featureSettings);
|
||||
}
|
||||
|
||||
// -- position
|
||||
aStyle->variantSubSuper = variantPosition;
|
||||
|
||||
// -- width
|
||||
setting.mTag = FontFeatureTagForVariantWidth(variantWidth);
|
||||
if (setting.mTag) {
|
||||
setting.mValue = 1;
|
||||
aStyle->featureSettings.AppendElement(setting);
|
||||
}
|
||||
|
||||
// indicate common-path case when neither variantCaps or variantSubSuper are set
|
||||
aStyle->noFallbackVariantFeatures =
|
||||
(aStyle->variantCaps == NS_FONT_VARIANT_CAPS_NORMAL) &&
|
||||
(variantPosition == NS_FONT_VARIANT_POSITION_NORMAL);
|
||||
|
||||
// add in features from font-feature-settings
|
||||
aStyle->featureSettings.AppendElements(fontFeatureSettings);
|
||||
|
||||
// enable grayscale antialiasing for text
|
||||
if (smoothing == NS_FONT_SMOOTHING_GRAYSCALE) {
|
||||
aStyle->useGrayscaleAntialiasing = true;
|
||||
}
|
||||
}
|
||||
147
gfx/src/nsFont.h
Normal file
147
gfx/src/nsFont.h
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
/* -*- 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 nsFont_h___
|
||||
#define nsFont_h___
|
||||
|
||||
#include <stdint.h> // for uint8_t, uint16_t
|
||||
#include <sys/types.h> // for int16_t
|
||||
#include "gfxFontFamilyList.h"
|
||||
#include "gfxFontFeatures.h"
|
||||
#include "mozilla/RefPtr.h" // for RefPtr
|
||||
#include "nsCoord.h" // for nscoord
|
||||
#include "nsStringFwd.h" // for nsSubstring
|
||||
#include "nsString.h" // for nsString
|
||||
#include "nsTArray.h" // for nsTArray
|
||||
|
||||
struct gfxFontStyle;
|
||||
|
||||
// XXX we need a method to enumerate all of the possible fonts on the
|
||||
// system across family, weight, style, size, etc. But not here!
|
||||
|
||||
// Enumerator callback function. Return false to stop
|
||||
typedef bool (*nsFontFamilyEnumFunc)(const nsString& aFamily, bool aGeneric, void *aData);
|
||||
|
||||
// IDs for generic fonts
|
||||
// NOTE: 0, 1 are reserved for the special IDs of the default variable
|
||||
// and fixed fonts in the presentation context, see nsPresContext.h
|
||||
const uint8_t kGenericFont_NONE = 0x00;
|
||||
// Special
|
||||
const uint8_t kGenericFont_moz_variable = 0x00; // for the default variable width font
|
||||
const uint8_t kGenericFont_moz_fixed = 0x01; // our special "use the user's fixed font"
|
||||
// CSS
|
||||
const uint8_t kGenericFont_serif = 0x02;
|
||||
const uint8_t kGenericFont_sans_serif = 0x04;
|
||||
const uint8_t kGenericFont_monospace = 0x08;
|
||||
const uint8_t kGenericFont_cursive = 0x10;
|
||||
const uint8_t kGenericFont_fantasy = 0x20;
|
||||
|
||||
// Font structure.
|
||||
struct nsFont {
|
||||
|
||||
// list of font families, either named or generic
|
||||
mozilla::FontFamilyList fontlist;
|
||||
|
||||
// The style of font (normal, italic, oblique; see gfxFontConstants.h)
|
||||
uint8_t style;
|
||||
|
||||
// Force this font to not be considered a 'generic' font, even if
|
||||
// the name is the same as a CSS generic font family.
|
||||
bool systemFont;
|
||||
|
||||
// Variant subproperties
|
||||
uint8_t variantCaps;
|
||||
uint8_t variantNumeric;
|
||||
uint8_t variantPosition;
|
||||
uint8_t variantWidth;
|
||||
|
||||
uint16_t variantLigatures;
|
||||
uint16_t variantEastAsian;
|
||||
|
||||
// Some font-variant-alternates property values require
|
||||
// font-specific settings defined via @font-feature-values rules.
|
||||
// These are resolved *after* font matching occurs.
|
||||
|
||||
// -- bitmask for both enumerated and functional propvals
|
||||
uint16_t variantAlternates;
|
||||
|
||||
// Smoothing - controls subpixel-antialiasing (currently OSX only)
|
||||
uint8_t smoothing;
|
||||
|
||||
// The weight of the font; see gfxFontConstants.h.
|
||||
uint16_t weight;
|
||||
|
||||
// The stretch of the font (the sum of various NS_FONT_STRETCH_*
|
||||
// constants; see gfxFontConstants.h).
|
||||
int16_t stretch;
|
||||
|
||||
// Kerning
|
||||
uint8_t kerning;
|
||||
|
||||
// Synthesis setting, controls use of fake bolding/italics
|
||||
uint8_t synthesis;
|
||||
|
||||
// The logical size of the font, in nscoord units
|
||||
nscoord size;
|
||||
|
||||
// The aspect-value (ie., the ratio actualsize:actualxheight) that any
|
||||
// actual physical font created from this font structure must have when
|
||||
// rendering or measuring a string. A value of -1.0 means no adjustment
|
||||
// needs to be done; otherwise the value must be nonnegative.
|
||||
float sizeAdjust;
|
||||
|
||||
// -- list of value tags for font-specific alternate features
|
||||
nsTArray<gfxAlternateValue> alternateValues;
|
||||
|
||||
// -- object used to look these up once the font is matched
|
||||
RefPtr<gfxFontFeatureValueSet> featureValueLookup;
|
||||
|
||||
// Font features from CSS font-feature-settings
|
||||
nsTArray<gfxFontFeature> fontFeatureSettings;
|
||||
|
||||
// Language system tag, to override document language;
|
||||
// this is an OpenType "language system" tag represented as a 32-bit integer
|
||||
// (see http://www.microsoft.com/typography/otspec/languagetags.htm).
|
||||
nsString languageOverride;
|
||||
|
||||
// initialize the font with a fontlist
|
||||
nsFont(const mozilla::FontFamilyList& aFontlist, nscoord aSize);
|
||||
|
||||
// initialize the font with a single generic
|
||||
nsFont(mozilla::FontFamilyType aGenericType, nscoord aSize);
|
||||
|
||||
// Make a copy of the given font
|
||||
nsFont(const nsFont& aFont);
|
||||
|
||||
// leave members uninitialized
|
||||
nsFont();
|
||||
|
||||
~nsFont();
|
||||
|
||||
bool operator==(const nsFont& aOther) const {
|
||||
return Equals(aOther);
|
||||
}
|
||||
|
||||
bool operator!=(const nsFont& aOther) const {
|
||||
return !Equals(aOther);
|
||||
}
|
||||
|
||||
bool Equals(const nsFont& aOther) const;
|
||||
|
||||
nsFont& operator=(const nsFont& aOther);
|
||||
|
||||
void CopyAlternates(const nsFont& aOther);
|
||||
|
||||
// Add featureSettings into style
|
||||
void AddFontFeaturesToStyle(gfxFontStyle *aStyle) const;
|
||||
|
||||
protected:
|
||||
void Init(); // helper method for initialization
|
||||
};
|
||||
|
||||
#define NS_FONT_VARIANT_NORMAL 0
|
||||
#define NS_FONT_VARIANT_SMALL_CAPS 1
|
||||
|
||||
#endif /* nsFont_h___ */
|
||||
445
gfx/src/nsFontMetrics.cpp
Normal file
445
gfx/src/nsFontMetrics.cpp
Normal file
|
|
@ -0,0 +1,445 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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/. */
|
||||
|
||||
#include "nsFontMetrics.h"
|
||||
#include <math.h> // for floor, ceil
|
||||
#include <algorithm> // for max
|
||||
#include "gfxFontConstants.h" // for NS_FONT_SYNTHESIS_*
|
||||
#include "gfxPlatform.h" // for gfxPlatform
|
||||
#include "gfxPoint.h" // for gfxPoint
|
||||
#include "gfxRect.h" // for gfxRect
|
||||
#include "gfxTypes.h" // for gfxFloat
|
||||
#include "nsBoundingMetrics.h" // for nsBoundingMetrics
|
||||
#include "nsDebug.h" // for NS_ERROR
|
||||
#include "nsDeviceContext.h" // for nsDeviceContext
|
||||
#include "nsIAtom.h" // for nsIAtom
|
||||
#include "nsMathUtils.h" // for NS_round
|
||||
#include "nsRenderingContext.h" // for nsRenderingContext
|
||||
#include "nsString.h" // for nsString
|
||||
#include "nsStyleConsts.h" // for NS_STYLE_HYPHENS_NONE
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT
|
||||
#include "mozilla/UniquePtr.h" // for UniquePtr
|
||||
|
||||
class gfxUserFontSet;
|
||||
using namespace mozilla;
|
||||
|
||||
namespace {
|
||||
|
||||
class AutoTextRun {
|
||||
public:
|
||||
typedef mozilla::gfx::DrawTarget DrawTarget;
|
||||
|
||||
AutoTextRun(nsFontMetrics* aMetrics, DrawTarget* aDrawTarget,
|
||||
const char* aString, int32_t aLength)
|
||||
{
|
||||
mTextRun = aMetrics->GetThebesFontGroup()->MakeTextRun(
|
||||
reinterpret_cast<const uint8_t*>(aString), aLength,
|
||||
aDrawTarget,
|
||||
aMetrics->AppUnitsPerDevPixel(),
|
||||
ComputeFlags(aMetrics),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
AutoTextRun(nsFontMetrics* aMetrics, DrawTarget* aDrawTarget,
|
||||
const char16_t* aString, int32_t aLength)
|
||||
{
|
||||
mTextRun = aMetrics->GetThebesFontGroup()->MakeTextRun(
|
||||
aString, aLength,
|
||||
aDrawTarget,
|
||||
aMetrics->AppUnitsPerDevPixel(),
|
||||
ComputeFlags(aMetrics),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
gfxTextRun *get() { return mTextRun.get(); }
|
||||
gfxTextRun *operator->() { return mTextRun.get(); }
|
||||
|
||||
private:
|
||||
static uint32_t ComputeFlags(nsFontMetrics* aMetrics) {
|
||||
uint32_t flags = 0;
|
||||
if (aMetrics->GetTextRunRTL()) {
|
||||
flags |= gfxTextRunFactory::TEXT_IS_RTL;
|
||||
}
|
||||
if (aMetrics->GetVertical()) {
|
||||
switch (aMetrics->GetTextOrientation()) {
|
||||
case NS_STYLE_TEXT_ORIENTATION_MIXED:
|
||||
flags |= gfxTextRunFactory::TEXT_ORIENT_VERTICAL_MIXED;
|
||||
break;
|
||||
case NS_STYLE_TEXT_ORIENTATION_UPRIGHT:
|
||||
flags |= gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT;
|
||||
break;
|
||||
case NS_STYLE_TEXT_ORIENTATION_SIDEWAYS:
|
||||
flags |= gfxTextRunFactory::TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
RefPtr<gfxTextRun> mTextRun;
|
||||
};
|
||||
|
||||
class StubPropertyProvider : public gfxTextRun::PropertyProvider {
|
||||
public:
|
||||
virtual void GetHyphenationBreaks(gfxTextRun::Range aRange,
|
||||
bool* aBreakBefore) {
|
||||
NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");
|
||||
}
|
||||
virtual int8_t GetHyphensOption() {
|
||||
NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");
|
||||
return NS_STYLE_HYPHENS_NONE;
|
||||
}
|
||||
virtual gfxFloat GetHyphenWidth() {
|
||||
NS_ERROR("This shouldn't be called because we never enable hyphens");
|
||||
return 0;
|
||||
}
|
||||
virtual already_AddRefed<mozilla::gfx::DrawTarget> GetDrawTarget() {
|
||||
NS_ERROR("This shouldn't be called because we never enable hyphens");
|
||||
return nullptr;
|
||||
}
|
||||
virtual uint32_t GetAppUnitsPerDevUnit() {
|
||||
NS_ERROR("This shouldn't be called because we never enable hyphens");
|
||||
return 60;
|
||||
}
|
||||
virtual void GetSpacing(gfxTextRun::Range aRange, Spacing* aSpacing) {
|
||||
NS_ERROR("This shouldn't be called because we never enable spacing");
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
nsFontMetrics::nsFontMetrics(const nsFont& aFont, const Params& aParams,
|
||||
nsDeviceContext *aContext)
|
||||
: mFont(aFont)
|
||||
, mLanguage(aParams.language)
|
||||
, mDeviceContext(aContext)
|
||||
, mP2A(aContext->AppUnitsPerDevPixel())
|
||||
, mOrientation(aParams.orientation)
|
||||
, mTextRunRTL(false)
|
||||
, mVertical(false)
|
||||
, mTextOrientation(0)
|
||||
{
|
||||
gfxFontStyle style(aFont.style,
|
||||
aFont.weight,
|
||||
aFont.stretch,
|
||||
gfxFloat(aFont.size) / mP2A,
|
||||
aParams.language,
|
||||
aParams.explicitLanguage,
|
||||
aFont.sizeAdjust,
|
||||
aFont.systemFont,
|
||||
mDeviceContext->IsPrinterContext(),
|
||||
aFont.synthesis & NS_FONT_SYNTHESIS_WEIGHT,
|
||||
aFont.synthesis & NS_FONT_SYNTHESIS_STYLE,
|
||||
aFont.languageOverride);
|
||||
|
||||
aFont.AddFontFeaturesToStyle(&style);
|
||||
|
||||
gfxFloat devToCssSize = gfxFloat(mP2A) /
|
||||
gfxFloat(mDeviceContext->AppUnitsPerCSSPixel());
|
||||
mFontGroup = gfxPlatform::GetPlatform()->
|
||||
CreateFontGroup(aFont.fontlist, &style, aParams.textPerf,
|
||||
aParams.userFontSet, devToCssSize);
|
||||
}
|
||||
|
||||
nsFontMetrics::~nsFontMetrics()
|
||||
{
|
||||
if (mDeviceContext) {
|
||||
mDeviceContext->FontMetricsDeleted(this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsFontMetrics::Destroy()
|
||||
{
|
||||
mDeviceContext = nullptr;
|
||||
}
|
||||
|
||||
// XXXTODO get rid of this macro
|
||||
#define ROUND_TO_TWIPS(x) (nscoord)floor(((x) * mP2A) + 0.5)
|
||||
#define CEIL_TO_TWIPS(x) (nscoord)ceil((x) * mP2A)
|
||||
|
||||
const gfxFont::Metrics&
|
||||
nsFontMetrics::GetMetrics(gfxFont::Orientation aOrientation) const
|
||||
{
|
||||
return mFontGroup->GetFirstValidFont()->GetMetrics(aOrientation);
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFontMetrics::XHeight()
|
||||
{
|
||||
return ROUND_TO_TWIPS(GetMetrics().xHeight);
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFontMetrics::CapHeight()
|
||||
{
|
||||
return ROUND_TO_TWIPS(GetMetrics().capHeight);
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFontMetrics::SuperscriptOffset()
|
||||
{
|
||||
return ROUND_TO_TWIPS(GetMetrics().emHeight *
|
||||
NS_FONT_SUPERSCRIPT_OFFSET_RATIO);
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFontMetrics::SubscriptOffset()
|
||||
{
|
||||
return ROUND_TO_TWIPS(GetMetrics().emHeight *
|
||||
NS_FONT_SUBSCRIPT_OFFSET_RATIO);
|
||||
}
|
||||
|
||||
void
|
||||
nsFontMetrics::GetStrikeout(nscoord& aOffset, nscoord& aSize)
|
||||
{
|
||||
aOffset = ROUND_TO_TWIPS(GetMetrics().strikeoutOffset);
|
||||
aSize = ROUND_TO_TWIPS(GetMetrics().strikeoutSize);
|
||||
}
|
||||
|
||||
void
|
||||
nsFontMetrics::GetUnderline(nscoord& aOffset, nscoord& aSize)
|
||||
{
|
||||
aOffset = ROUND_TO_TWIPS(mFontGroup->GetUnderlineOffset());
|
||||
aSize = ROUND_TO_TWIPS(GetMetrics().underlineSize);
|
||||
}
|
||||
|
||||
// GetMaxAscent/GetMaxDescent/GetMaxHeight must contain the
|
||||
// text-decoration lines drawable area. See bug 421353.
|
||||
// BE CAREFUL for rounding each values. The logic MUST be same as
|
||||
// nsCSSRendering::GetTextDecorationRectInternal's.
|
||||
|
||||
static gfxFloat ComputeMaxDescent(const gfxFont::Metrics& aMetrics,
|
||||
gfxFontGroup* aFontGroup)
|
||||
{
|
||||
gfxFloat offset = floor(-aFontGroup->GetUnderlineOffset() + 0.5);
|
||||
gfxFloat size = NS_round(aMetrics.underlineSize);
|
||||
gfxFloat minDescent = offset + size;
|
||||
return floor(std::max(minDescent, aMetrics.maxDescent) + 0.5);
|
||||
}
|
||||
|
||||
static gfxFloat ComputeMaxAscent(const gfxFont::Metrics& aMetrics)
|
||||
{
|
||||
return floor(aMetrics.maxAscent + 0.5);
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFontMetrics::InternalLeading()
|
||||
{
|
||||
return ROUND_TO_TWIPS(GetMetrics().internalLeading);
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFontMetrics::ExternalLeading()
|
||||
{
|
||||
return ROUND_TO_TWIPS(GetMetrics().externalLeading);
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFontMetrics::EmHeight()
|
||||
{
|
||||
return ROUND_TO_TWIPS(GetMetrics().emHeight);
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFontMetrics::EmAscent()
|
||||
{
|
||||
return ROUND_TO_TWIPS(GetMetrics().emAscent);
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFontMetrics::EmDescent()
|
||||
{
|
||||
return ROUND_TO_TWIPS(GetMetrics().emDescent);
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFontMetrics::MaxHeight()
|
||||
{
|
||||
return CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics())) +
|
||||
CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup));
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFontMetrics::MaxAscent()
|
||||
{
|
||||
return CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics()));
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFontMetrics::MaxDescent()
|
||||
{
|
||||
return CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup));
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFontMetrics::MaxAdvance()
|
||||
{
|
||||
return CEIL_TO_TWIPS(GetMetrics().maxAdvance);
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFontMetrics::AveCharWidth()
|
||||
{
|
||||
// Use CEIL instead of ROUND for consistency with GetMaxAdvance
|
||||
return CEIL_TO_TWIPS(GetMetrics().aveCharWidth);
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFontMetrics::SpaceWidth()
|
||||
{
|
||||
// For vertical text with mixed or sideways orientation, we want the
|
||||
// width of a horizontal space (even if we're using vertical line-spacing
|
||||
// metrics, as with "writing-mode:vertical-*;text-orientation:mixed").
|
||||
return CEIL_TO_TWIPS(
|
||||
GetMetrics(mVertical &&
|
||||
mTextOrientation == NS_STYLE_TEXT_ORIENTATION_UPRIGHT
|
||||
? gfxFont::eVertical
|
||||
: gfxFont::eHorizontal).spaceWidth);
|
||||
}
|
||||
|
||||
int32_t
|
||||
nsFontMetrics::GetMaxStringLength()
|
||||
{
|
||||
const gfxFont::Metrics& m = GetMetrics();
|
||||
const double x = 32767.0 / m.maxAdvance;
|
||||
int32_t len = (int32_t)floor(x);
|
||||
return std::max(1, len);
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFontMetrics::GetWidth(const char* aString, uint32_t aLength,
|
||||
DrawTarget* aDrawTarget)
|
||||
{
|
||||
if (aLength == 0)
|
||||
return 0;
|
||||
|
||||
if (aLength == 1 && aString[0] == ' ')
|
||||
return SpaceWidth();
|
||||
|
||||
StubPropertyProvider provider;
|
||||
AutoTextRun textRun(this, aDrawTarget, aString, aLength);
|
||||
if (textRun.get()) {
|
||||
return NSToCoordRound(
|
||||
textRun->GetAdvanceWidth(Range(0, aLength), &provider));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFontMetrics::GetWidth(const char16_t* aString, uint32_t aLength,
|
||||
DrawTarget* aDrawTarget)
|
||||
{
|
||||
if (aLength == 0)
|
||||
return 0;
|
||||
|
||||
if (aLength == 1 && aString[0] == ' ')
|
||||
return SpaceWidth();
|
||||
|
||||
StubPropertyProvider provider;
|
||||
AutoTextRun textRun(this, aDrawTarget, aString, aLength);
|
||||
if (textRun.get()) {
|
||||
return NSToCoordRound(
|
||||
textRun->GetAdvanceWidth(Range(0, aLength), &provider));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Draw a string using this font handle on the surface passed in.
|
||||
void
|
||||
nsFontMetrics::DrawString(const char *aString, uint32_t aLength,
|
||||
nscoord aX, nscoord aY,
|
||||
nsRenderingContext *aContext)
|
||||
{
|
||||
if (aLength == 0)
|
||||
return;
|
||||
|
||||
StubPropertyProvider provider;
|
||||
AutoTextRun textRun(this, aContext->GetDrawTarget(), aString, aLength);
|
||||
if (!textRun.get()) {
|
||||
return;
|
||||
}
|
||||
gfxPoint pt(aX, aY);
|
||||
Range range(0, aLength);
|
||||
if (mTextRunRTL) {
|
||||
if (mVertical) {
|
||||
pt.y += textRun->GetAdvanceWidth(range, &provider);
|
||||
} else {
|
||||
pt.x += textRun->GetAdvanceWidth(range, &provider);
|
||||
}
|
||||
}
|
||||
gfxTextRun::DrawParams params(aContext->ThebesContext());
|
||||
params.provider = &provider;
|
||||
textRun->Draw(range, pt, params);
|
||||
}
|
||||
|
||||
void
|
||||
nsFontMetrics::DrawString(const char16_t* aString, uint32_t aLength,
|
||||
nscoord aX, nscoord aY,
|
||||
nsRenderingContext *aContext,
|
||||
DrawTarget* aTextRunConstructionDrawTarget)
|
||||
{
|
||||
if (aLength == 0)
|
||||
return;
|
||||
|
||||
StubPropertyProvider provider;
|
||||
AutoTextRun textRun(this, aTextRunConstructionDrawTarget, aString, aLength);
|
||||
if (!textRun.get()) {
|
||||
return;
|
||||
}
|
||||
gfxPoint pt(aX, aY);
|
||||
Range range(0, aLength);
|
||||
if (mTextRunRTL) {
|
||||
if (mVertical) {
|
||||
pt.y += textRun->GetAdvanceWidth(range, &provider);
|
||||
} else {
|
||||
pt.x += textRun->GetAdvanceWidth(range, &provider);
|
||||
}
|
||||
}
|
||||
gfxTextRun::DrawParams params(aContext->ThebesContext());
|
||||
params.provider = &provider;
|
||||
textRun->Draw(range, pt, params);
|
||||
}
|
||||
|
||||
static nsBoundingMetrics
|
||||
GetTextBoundingMetrics(nsFontMetrics* aMetrics, const char16_t* aString,
|
||||
uint32_t aLength, mozilla::gfx::DrawTarget* aDrawTarget,
|
||||
gfxFont::BoundingBoxType aType)
|
||||
{
|
||||
if (aLength == 0)
|
||||
return nsBoundingMetrics();
|
||||
|
||||
StubPropertyProvider provider;
|
||||
AutoTextRun textRun(aMetrics, aDrawTarget, aString, aLength);
|
||||
nsBoundingMetrics m;
|
||||
if (textRun.get()) {
|
||||
gfxTextRun::Metrics theMetrics = textRun->MeasureText(
|
||||
gfxTextRun::Range(0, aLength), aType, aDrawTarget, &provider);
|
||||
|
||||
m.leftBearing = NSToCoordFloor( theMetrics.mBoundingBox.X());
|
||||
m.rightBearing = NSToCoordCeil( theMetrics.mBoundingBox.XMost());
|
||||
m.ascent = NSToCoordCeil( -theMetrics.mBoundingBox.Y());
|
||||
m.descent = NSToCoordCeil( theMetrics.mBoundingBox.YMost());
|
||||
m.width = NSToCoordRound( theMetrics.mAdvanceWidth);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
nsBoundingMetrics
|
||||
nsFontMetrics::GetBoundingMetrics(const char16_t *aString, uint32_t aLength,
|
||||
DrawTarget* aDrawTarget)
|
||||
{
|
||||
return GetTextBoundingMetrics(this, aString, aLength, aDrawTarget,
|
||||
gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS);
|
||||
}
|
||||
|
||||
nsBoundingMetrics
|
||||
nsFontMetrics::GetInkBoundsForVisualOverflow(const char16_t *aString, uint32_t aLength,
|
||||
DrawTarget* aDrawTarget)
|
||||
{
|
||||
return GetTextBoundingMetrics(this, aString, aLength, aDrawTarget,
|
||||
gfxFont::LOOSE_INK_EXTENTS);
|
||||
}
|
||||
|
||||
268
gfx/src/nsFontMetrics.h
Normal file
268
gfx/src/nsFontMetrics.h
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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 NSFONTMETRICS__H__
|
||||
#define NSFONTMETRICS__H__
|
||||
|
||||
#include <stdint.h> // for uint32_t
|
||||
#include <sys/types.h> // for int32_t
|
||||
#include "gfxTextRun.h" // for gfxFont, gfxFontGroup
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
|
||||
#include "mozilla/RefPtr.h" // for RefPtr
|
||||
#include "nsCOMPtr.h" // for nsCOMPtr
|
||||
#include "nsCoord.h" // for nscoord
|
||||
#include "nsError.h" // for nsresult
|
||||
#include "nsFont.h" // for nsFont
|
||||
#include "nsISupports.h" // for NS_INLINE_DECL_REFCOUNTING
|
||||
#include "nscore.h" // for char16_t
|
||||
|
||||
class gfxUserFontSet;
|
||||
class gfxTextPerfMetrics;
|
||||
class nsDeviceContext;
|
||||
class nsIAtom;
|
||||
class nsRenderingContext;
|
||||
struct nsBoundingMetrics;
|
||||
|
||||
/**
|
||||
* Font metrics
|
||||
*
|
||||
* This class may be somewhat misnamed. A better name might be
|
||||
* nsFontList. The style system uses the nsFont struct for various
|
||||
* font properties, one of which is font-family, which can contain a
|
||||
* *list* of font names. The nsFont struct is "realized" by asking the
|
||||
* device context to cough up an nsFontMetrics object, which contains
|
||||
* a list of real font handles, one for each font mentioned in
|
||||
* font-family (and for each fallback when we fall off the end of that
|
||||
* list).
|
||||
*
|
||||
* The style system needs to have access to certain metrics, such as
|
||||
* the em height (for the CSS "em" unit), and we use the first Western
|
||||
* font's metrics for that purpose. The platform-specific
|
||||
* implementations are expected to select non-Western fonts that "fit"
|
||||
* reasonably well with the Western font that is loaded at Init time.
|
||||
*/
|
||||
class nsFontMetrics final
|
||||
{
|
||||
public:
|
||||
typedef gfxTextRun::Range Range;
|
||||
typedef mozilla::gfx::DrawTarget DrawTarget;
|
||||
|
||||
struct Params
|
||||
{
|
||||
nsIAtom* language = nullptr;
|
||||
bool explicitLanguage = false;
|
||||
gfxFont::Orientation orientation = gfxFont::eHorizontal;
|
||||
gfxUserFontSet* userFontSet = nullptr;
|
||||
gfxTextPerfMetrics* textPerf = nullptr;
|
||||
};
|
||||
|
||||
nsFontMetrics(const nsFont& aFont, const Params& aParams,
|
||||
nsDeviceContext *aContext);
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(nsFontMetrics)
|
||||
|
||||
/**
|
||||
* Destroy this font metrics. This breaks the association between
|
||||
* the font metrics and the device context.
|
||||
*/
|
||||
void Destroy();
|
||||
|
||||
/**
|
||||
* Return the font's x-height.
|
||||
*/
|
||||
nscoord XHeight();
|
||||
|
||||
/**
|
||||
* Return the font's cap-height.
|
||||
*/
|
||||
nscoord CapHeight();
|
||||
|
||||
/**
|
||||
* Return the font's superscript offset (the distance from the
|
||||
* baseline to where a superscript's baseline should be placed).
|
||||
* The value returned will be positive.
|
||||
*/
|
||||
nscoord SuperscriptOffset();
|
||||
|
||||
/**
|
||||
* Return the font's subscript offset (the distance from the
|
||||
* baseline to where a subscript's baseline should be placed).
|
||||
* The value returned will be positive.
|
||||
*/
|
||||
nscoord SubscriptOffset();
|
||||
|
||||
/**
|
||||
* Return the font's strikeout offset (the distance from the
|
||||
* baseline to where a strikeout should be placed) and size.
|
||||
* Positive values are above the baseline, negative below.
|
||||
*/
|
||||
void GetStrikeout(nscoord& aOffset, nscoord& aSize);
|
||||
|
||||
/**
|
||||
* Return the font's underline offset (the distance from the
|
||||
* baseline to where a underline should be placed) and size.
|
||||
* Positive values are above the baseline, negative below.
|
||||
*/
|
||||
void GetUnderline(nscoord& aOffset, nscoord& aSize);
|
||||
|
||||
/**
|
||||
* Returns the amount of internal leading for the font.
|
||||
* This is normally the difference between the max ascent
|
||||
* and the em ascent.
|
||||
*/
|
||||
nscoord InternalLeading();
|
||||
|
||||
/**
|
||||
* Returns the amount of external leading for the font.
|
||||
* em ascent(?) plus external leading is the font designer's
|
||||
* recommended line-height for this font.
|
||||
*/
|
||||
nscoord ExternalLeading();
|
||||
|
||||
/**
|
||||
* Returns the height of the em square.
|
||||
* This is em ascent plus em descent.
|
||||
*/
|
||||
nscoord EmHeight();
|
||||
|
||||
/**
|
||||
* Returns the ascent part of the em square.
|
||||
*/
|
||||
nscoord EmAscent();
|
||||
|
||||
/**
|
||||
* Returns the descent part of the em square.
|
||||
*/
|
||||
nscoord EmDescent();
|
||||
|
||||
/**
|
||||
* Returns the height of the bounding box.
|
||||
* This is max ascent plus max descent.
|
||||
*/
|
||||
nscoord MaxHeight();
|
||||
|
||||
/**
|
||||
* Returns the maximum distance characters in this font extend
|
||||
* above the base line.
|
||||
*/
|
||||
nscoord MaxAscent();
|
||||
|
||||
/**
|
||||
* Returns the maximum distance characters in this font extend
|
||||
* below the base line.
|
||||
*/
|
||||
nscoord MaxDescent();
|
||||
|
||||
/**
|
||||
* Returns the maximum character advance for the font.
|
||||
*/
|
||||
nscoord MaxAdvance();
|
||||
|
||||
/**
|
||||
* Returns the average character width
|
||||
*/
|
||||
nscoord AveCharWidth();
|
||||
|
||||
/**
|
||||
* Returns the often needed width of the space character
|
||||
*/
|
||||
nscoord SpaceWidth();
|
||||
|
||||
/**
|
||||
* Returns the font associated with these metrics. The return value
|
||||
* is only defined after Init() has been called.
|
||||
*/
|
||||
const nsFont &Font() const { return mFont; }
|
||||
|
||||
/**
|
||||
* Returns the language associated with these metrics
|
||||
*/
|
||||
nsIAtom* Language() const { return mLanguage; }
|
||||
|
||||
/**
|
||||
* Returns the orientation (horizontal/vertical) of these metrics.
|
||||
*/
|
||||
gfxFont::Orientation Orientation() const { return mOrientation; }
|
||||
|
||||
int32_t GetMaxStringLength();
|
||||
|
||||
// Get the width for this string. aWidth will be updated with the
|
||||
// width in points, not twips. Callers must convert it if they
|
||||
// want it in another format.
|
||||
nscoord GetWidth(const char* aString, uint32_t aLength,
|
||||
DrawTarget* aDrawTarget);
|
||||
nscoord GetWidth(const char16_t* aString, uint32_t aLength,
|
||||
DrawTarget* aDrawTarget);
|
||||
|
||||
// Draw a string using this font handle on the surface passed in.
|
||||
void DrawString(const char *aString, uint32_t aLength,
|
||||
nscoord aX, nscoord aY,
|
||||
nsRenderingContext *aContext);
|
||||
void DrawString(const char16_t* aString, uint32_t aLength,
|
||||
nscoord aX, nscoord aY,
|
||||
nsRenderingContext *aContext,
|
||||
DrawTarget* aTextRunConstructionDrawTarget);
|
||||
|
||||
nsBoundingMetrics GetBoundingMetrics(const char16_t *aString,
|
||||
uint32_t aLength,
|
||||
DrawTarget* aDrawTarget);
|
||||
|
||||
// Returns the LOOSE_INK_EXTENTS bounds of the text for determing the
|
||||
// overflow area of the string.
|
||||
nsBoundingMetrics GetInkBoundsForVisualOverflow(const char16_t *aString,
|
||||
uint32_t aLength,
|
||||
DrawTarget* aDrawTarget);
|
||||
|
||||
void SetTextRunRTL(bool aIsRTL) { mTextRunRTL = aIsRTL; }
|
||||
bool GetTextRunRTL() const { return mTextRunRTL; }
|
||||
|
||||
void SetVertical(bool aVertical) { mVertical = aVertical; }
|
||||
bool GetVertical() const { return mVertical; }
|
||||
|
||||
void SetTextOrientation(uint8_t aTextOrientation)
|
||||
{
|
||||
mTextOrientation = aTextOrientation;
|
||||
}
|
||||
uint8_t GetTextOrientation() const { return mTextOrientation; }
|
||||
|
||||
gfxFontGroup* GetThebesFontGroup() const { return mFontGroup; }
|
||||
gfxUserFontSet* GetUserFontSet() const
|
||||
{
|
||||
return mFontGroup->GetUserFontSet();
|
||||
}
|
||||
|
||||
int32_t AppUnitsPerDevPixel() const { return mP2A; }
|
||||
|
||||
private:
|
||||
// Private destructor, to discourage deletion outside of Release():
|
||||
~nsFontMetrics();
|
||||
|
||||
const gfxFont::Metrics& GetMetrics() const {
|
||||
return GetMetrics(mOrientation);
|
||||
}
|
||||
|
||||
const gfxFont::Metrics&
|
||||
GetMetrics(const gfxFont::Orientation aFontOrientation) const;
|
||||
|
||||
nsFont mFont;
|
||||
RefPtr<gfxFontGroup> mFontGroup;
|
||||
nsCOMPtr<nsIAtom> mLanguage;
|
||||
nsDeviceContext* mDeviceContext;
|
||||
int32_t mP2A;
|
||||
|
||||
// The font orientation (horizontal or vertical) for which these metrics
|
||||
// have been initialized. This determines which line metrics (ascent and
|
||||
// descent) they will return.
|
||||
gfxFont::Orientation mOrientation;
|
||||
|
||||
// These fields may be set by clients to control the behavior of methods
|
||||
// like GetWidth and DrawString according to the writing mode, direction
|
||||
// and text-orientation desired.
|
||||
bool mTextRunRTL;
|
||||
bool mVertical;
|
||||
uint8_t mTextOrientation;
|
||||
};
|
||||
|
||||
#endif /* NSFONTMETRICS__H__ */
|
||||
21
gfx/src/nsGfxCIID.h
Normal file
21
gfx/src/nsGfxCIID.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/* -*- 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 nsGfxCIID_h__
|
||||
#define nsGfxCIID_h__
|
||||
|
||||
#define NS_FONT_ENUMERATOR_CID \
|
||||
{ 0xa6cf9115, 0x15b3, 0x11d2, \
|
||||
{ 0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32 } }
|
||||
|
||||
#define NS_SCRIPTABLE_REGION_CID \
|
||||
{ 0xda5b130a, 0x1dd1, 0x11b2, \
|
||||
{ 0xad, 0x47, 0xf4, 0x55, 0xb1, 0x81, 0x4a, 0x78 } }
|
||||
|
||||
#define NS_GFX_INITIALIZATION_CID \
|
||||
{ 0x67c41576, 0x9664, 0x4ed5, \
|
||||
{ 0x90, 0xc1, 0xf6, 0x68, 0x3f, 0xd5, 0x2c, 0x8f } }
|
||||
|
||||
#endif
|
||||
61
gfx/src/nsIFontEnumerator.idl
Normal file
61
gfx/src/nsIFontEnumerator.idl
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/* -*- Mode: IDL; 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 "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(924d98d9-3518-4cb4-8708-c74fe8e3ec3c)]
|
||||
interface nsIFontEnumerator : nsISupports
|
||||
{
|
||||
/**
|
||||
* Return a sorted array of the names of all installed fonts.
|
||||
*
|
||||
* @param aCount returns number of names returned
|
||||
* @param aResult returns array of names
|
||||
* @return void
|
||||
*/
|
||||
void EnumerateAllFonts(out uint32_t aCount,
|
||||
[retval, array, size_is(aCount)] out wstring aResult);
|
||||
|
||||
/**
|
||||
* Return a sorted array of names of fonts that support the given language
|
||||
* group and are suitable for use as the given CSS generic font.
|
||||
*
|
||||
* @param aLangGroup language group
|
||||
* @param aGeneric CSS generic font
|
||||
* @param aCount returns number of names returned
|
||||
* @param aResult returns array of names
|
||||
* @return void
|
||||
*/
|
||||
void EnumerateFonts(in string aLangGroup, in string aGeneric,
|
||||
out uint32_t aCount, [retval, array, size_is(aCount)] out wstring aResult);
|
||||
|
||||
/**
|
||||
@param aLangGroup language group
|
||||
@return bool do we have a font for this language group
|
||||
*/
|
||||
void HaveFontFor(in string aLangGroup, [retval] out boolean aResult);
|
||||
|
||||
/**
|
||||
* @param aLangGroup language group
|
||||
* @param aGeneric CSS generic font
|
||||
* @return suggested default font for this language group and generic family
|
||||
*/
|
||||
wstring getDefaultFont(in string aLangGroup, in string aGeneric);
|
||||
|
||||
/**
|
||||
* update the global font list
|
||||
* return true if font list is changed
|
||||
*/
|
||||
boolean updateFontList();
|
||||
|
||||
/**
|
||||
* get the standard family name on the system from given family
|
||||
* @param aName family name which may be alias
|
||||
* @return the standard family name on the system, if given name does not
|
||||
* exist, returns empty string
|
||||
*/
|
||||
wstring getStandardFamilyName(in wstring aName);
|
||||
};
|
||||
176
gfx/src/nsIScriptableRegion.idl
Normal file
176
gfx/src/nsIScriptableRegion.idl
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
/* -*- Mode: IDL; 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 "nsISupports.idl"
|
||||
|
||||
%{C++
|
||||
#include "nsRegionFwd.h"
|
||||
%}
|
||||
|
||||
native nsIntRegion(nsIntRegion);
|
||||
|
||||
|
||||
[scriptable, uuid(a5f44cc7-2820-489b-b817-ae8a08506ff6)]
|
||||
interface nsIScriptableRegion : nsISupports
|
||||
{
|
||||
void init ( ) ;
|
||||
|
||||
/**
|
||||
* copy operator equivalent that takes another region
|
||||
*
|
||||
* @param region to copy
|
||||
* @return void
|
||||
*
|
||||
**/
|
||||
|
||||
void setToRegion ( in nsIScriptableRegion aRegion );
|
||||
|
||||
/**
|
||||
* copy operator equivalent that takes a rect
|
||||
*
|
||||
* @param aX xoffset of rect to set region to
|
||||
* @param aY yoffset of rect to set region to
|
||||
* @param aWidth width of rect to set region to
|
||||
* @param aHeight height of rect to set region to
|
||||
* @return void
|
||||
*
|
||||
**/
|
||||
|
||||
void setToRect ( in long aX, in long aY, in long aWidth, in long aHeight );
|
||||
|
||||
/**
|
||||
* destructively intersect another region with this one
|
||||
*
|
||||
* @param region to intersect
|
||||
* @return void
|
||||
*
|
||||
**/
|
||||
|
||||
void intersectRegion ( in nsIScriptableRegion aRegion ) ;
|
||||
|
||||
/**
|
||||
* destructively intersect a rect with this region
|
||||
*
|
||||
* @param aX xoffset of rect to intersect with region
|
||||
* @param aY yoffset of rect to intersect with region
|
||||
* @param aWidth width of rect to intersect with region
|
||||
* @param aHeight height of rect to intersect with region
|
||||
* @return void
|
||||
*
|
||||
**/
|
||||
|
||||
void intersectRect ( in long aX, in long aY, in long aWidth, in long aHeight ) ;
|
||||
|
||||
/**
|
||||
* destructively union another region with this one
|
||||
*
|
||||
* @param region to union
|
||||
* @return void
|
||||
*
|
||||
**/
|
||||
|
||||
void unionRegion ( in nsIScriptableRegion aRegion ) ;
|
||||
|
||||
/**
|
||||
* destructively union a rect with this region
|
||||
*
|
||||
* @param aX xoffset of rect to union with region
|
||||
* @param aY yoffset of rect to union with region
|
||||
* @param aWidth width of rect to union with region
|
||||
* @param aHeight height of rect to union with region
|
||||
* @return void
|
||||
*
|
||||
**/
|
||||
|
||||
void unionRect ( in long aX, in long aY, in long aWidth, in long aHeight ) ;
|
||||
|
||||
/**
|
||||
* destructively subtract another region with this one
|
||||
*
|
||||
* @param region to subtract
|
||||
* @return void
|
||||
*
|
||||
**/
|
||||
|
||||
void subtractRegion ( in nsIScriptableRegion aRegion ) ;
|
||||
|
||||
/**
|
||||
* destructively subtract a rect from this region
|
||||
*
|
||||
* @param aX xoffset of rect to subtract with region
|
||||
* @param aY yoffset of rect to subtract with region
|
||||
* @param aWidth width of rect to subtract with region
|
||||
* @param aHeight height of rect to subtract with region
|
||||
* @return void
|
||||
*
|
||||
**/
|
||||
|
||||
void subtractRect ( in long aX, in long aY, in long aWidth, in long aHeight ) ;
|
||||
|
||||
/**
|
||||
* is this region empty? i.e. does it contain any pixels
|
||||
*
|
||||
* @param none
|
||||
* @return returns whether the region is empty
|
||||
*
|
||||
**/
|
||||
|
||||
boolean isEmpty ( ) ;
|
||||
|
||||
/**
|
||||
* == operator equivalent i.e. do the regions contain exactly
|
||||
* the same pixels
|
||||
*
|
||||
* @param region to compare
|
||||
* @return whether the regions are identical
|
||||
*
|
||||
**/
|
||||
|
||||
boolean isEqualRegion ( in nsIScriptableRegion aRegion ) ;
|
||||
|
||||
/**
|
||||
* returns the bounding box of the region i.e. the smallest
|
||||
* rectangle that completely contains the region.
|
||||
*
|
||||
* @param aX out parameter for xoffset of bounding rect for region
|
||||
* @param aY out parameter for yoffset of bounding rect for region
|
||||
* @param aWidth out parameter for width of bounding rect for region
|
||||
* @param aHeight out parameter for height of bounding rect for region
|
||||
* @return void
|
||||
*
|
||||
**/
|
||||
void getBoundingBox ( out long aX, out long aY, out long aWidth, out long aHeight ) ;
|
||||
|
||||
/**
|
||||
* offsets the region in x and y
|
||||
*
|
||||
* @param xoffset pixel offset in x
|
||||
* @param yoffset pixel offset in y
|
||||
* @return void
|
||||
*
|
||||
**/
|
||||
void offset ( in long aXOffset, in long aYOffset ) ;
|
||||
|
||||
/**
|
||||
* @return null if there are no rects,
|
||||
* @return flat array of rects,ie [x1,y1,width1,height1,x2...].
|
||||
* The result will contain bogus data if values don't fit in 31 bit
|
||||
**/
|
||||
[implicit_jscontext] jsval getRects();
|
||||
|
||||
/**
|
||||
* does the region intersect the rectangle?
|
||||
*
|
||||
* @param rect to check for containment
|
||||
* @return true if the region intersects the rect
|
||||
*
|
||||
**/
|
||||
|
||||
boolean containsRect ( in long aX, in long aY, in long aWidth, in long aHeight ) ;
|
||||
|
||||
[noscript] readonly attribute nsIntRegion region;
|
||||
|
||||
};
|
||||
206
gfx/src/nsITheme.h
Normal file
206
gfx/src/nsITheme.h
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
/* service providing platform-specific native rendering for widgets */
|
||||
|
||||
#ifndef nsITheme_h_
|
||||
#define nsITheme_h_
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsColor.h"
|
||||
#include "Units.h"
|
||||
|
||||
struct nsRect;
|
||||
class nsAttrValue;
|
||||
class nsPresContext;
|
||||
class nsRenderingContext;
|
||||
class nsDeviceContext;
|
||||
class nsIFrame;
|
||||
class nsIAtom;
|
||||
class nsIWidget;
|
||||
|
||||
// IID for the nsITheme interface
|
||||
// {7329f760-08cb-450f-8225-dae729096dec}
|
||||
#define NS_ITHEME_IID \
|
||||
{ 0x7329f760, 0x08cb, 0x450f, \
|
||||
{ 0x82, 0x25, 0xda, 0xe7, 0x29, 0x09, 0x6d, 0xec } }
|
||||
// {0ae05515-cf7a-45a8-9e02-6556de7685b1}
|
||||
#define NS_THEMERENDERER_CID \
|
||||
{ 0x0ae05515, 0xcf7a, 0x45a8, \
|
||||
{ 0x9e, 0x02, 0x65, 0x56, 0xde, 0x76, 0x85, 0xb1 } }
|
||||
|
||||
/**
|
||||
* nsITheme is a service that provides platform-specific native
|
||||
* rendering for widgets. In other words, it provides the necessary
|
||||
* operations to draw a rendering object (an nsIFrame) as a native
|
||||
* widget.
|
||||
*
|
||||
* All the methods on nsITheme take a rendering context or device
|
||||
* context, a frame (the rendering object), and a widget type (one of
|
||||
* the constants in nsThemeConstants.h).
|
||||
*/
|
||||
class nsITheme: public nsISupports {
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ITHEME_IID)
|
||||
|
||||
/**
|
||||
* Draw the actual theme background.
|
||||
* @param aContext the context to draw into
|
||||
* @param aFrame the frame for the widget that we're drawing
|
||||
* @param aWidgetType the -moz-appearance value to draw
|
||||
* @param aRect the rectangle defining the area occupied by the widget
|
||||
* @param aDirtyRect the rectangle that needs to be drawn
|
||||
*/
|
||||
NS_IMETHOD DrawWidgetBackground(nsRenderingContext* aContext,
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType,
|
||||
const nsRect& aRect,
|
||||
const nsRect& aDirtyRect) = 0;
|
||||
|
||||
/**
|
||||
* Get the computed CSS border for the widget, in pixels.
|
||||
*/
|
||||
NS_IMETHOD GetWidgetBorder(nsDeviceContext* aContext,
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType,
|
||||
nsIntMargin* aResult)=0;
|
||||
|
||||
/**
|
||||
* This method can return false to indicate that the CSS padding
|
||||
* value should be used. Otherwise, it will fill in aResult with the
|
||||
* computed padding, in pixels, and return true.
|
||||
*
|
||||
* XXXldb This ought to be required to return true for non-containers
|
||||
* so that we don't let specified padding that has no effect change
|
||||
* the computed padding and potentially the size.
|
||||
*/
|
||||
virtual bool GetWidgetPadding(nsDeviceContext* aContext,
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType,
|
||||
nsIntMargin* aResult) = 0;
|
||||
|
||||
/**
|
||||
* On entry, *aResult is positioned at 0,0 and sized to the new size
|
||||
* of aFrame (aFrame->GetSize() may be stale and should not be used).
|
||||
* This method can return false to indicate that no special
|
||||
* overflow area is required by the native widget. Otherwise it will
|
||||
* fill in aResult with the desired overflow area, in appunits, relative
|
||||
* to the frame origin, and return true.
|
||||
*
|
||||
* This overflow area is used to determine what area needs to be
|
||||
* repainted when the widget changes. However, it does not affect the
|
||||
* widget's size or what area is reachable by scrollbars. (In other
|
||||
* words, in layout terms, it affects visual overflow but not
|
||||
* scrollable overflow.)
|
||||
*/
|
||||
virtual bool GetWidgetOverflow(nsDeviceContext* aContext,
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType,
|
||||
/*INOUT*/ nsRect* aOverflowRect)
|
||||
{ return false; }
|
||||
|
||||
/**
|
||||
* Get the minimum border-box size of a widget, in *pixels* (in
|
||||
* |aResult|). If |aIsOverridable| is set to true, this size is a
|
||||
* minimum size; if false, this size is the only valid size for the
|
||||
* widget.
|
||||
*/
|
||||
NS_IMETHOD GetMinimumWidgetSize(nsPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType,
|
||||
mozilla::LayoutDeviceIntSize* aResult,
|
||||
bool* aIsOverridable)=0;
|
||||
|
||||
|
||||
enum Transparency {
|
||||
eOpaque = 0,
|
||||
eTransparent,
|
||||
eUnknownTransparency
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns what we know about the transparency of the widget.
|
||||
*/
|
||||
virtual Transparency GetWidgetTransparency(nsIFrame* aFrame, uint8_t aWidgetType)
|
||||
{ return eUnknownTransparency; }
|
||||
|
||||
NS_IMETHOD WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType,
|
||||
nsIAtom* aAttribute, bool* aShouldRepaint,
|
||||
const nsAttrValue* aOldValue)=0;
|
||||
|
||||
NS_IMETHOD ThemeChanged()=0;
|
||||
|
||||
virtual bool WidgetAppearanceDependsOnWindowFocus(uint8_t aWidgetType)
|
||||
{ return false; }
|
||||
|
||||
virtual bool NeedToClearBackgroundBehindWidget(nsIFrame* aFrame,
|
||||
uint8_t aWidgetType)
|
||||
{ return false; }
|
||||
|
||||
virtual bool WidgetProvidesFontSmoothingBackgroundColor(nsIFrame* aFrame,
|
||||
uint8_t aWidgetType, nscolor* aColor)
|
||||
{ return false; }
|
||||
|
||||
/**
|
||||
* ThemeGeometryType values are used for describing themed nsIFrames in
|
||||
* calls to nsIWidget::UpdateThemeGeometries. We don't simply pass the
|
||||
* -moz-appearance value ("widget type") of the frame because the widget may
|
||||
* want to treat different frames with the same -moz-appearance differently
|
||||
* based on other properties of the frame. So we give the theme a first look
|
||||
* at the frame in nsITheme::ThemeGeometryTypeForWidget and pass the
|
||||
* returned ThemeGeometryType along to the widget.
|
||||
* Each theme backend defines the ThemeGeometryType values it needs in its
|
||||
* own nsITheme subclass. eThemeGeometryTypeUnknown is the only value that's
|
||||
* shared between backends.
|
||||
*/
|
||||
typedef uint8_t ThemeGeometryType;
|
||||
enum {
|
||||
eThemeGeometryTypeUnknown = 0
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the theme geometry type that should be used in the ThemeGeometry
|
||||
* array that's passed to the widget using nsIWidget::UpdateThemeGeometries.
|
||||
* A return value of eThemeGeometryTypeUnknown means that this frame will
|
||||
* not be included in the ThemeGeometry array.
|
||||
*/
|
||||
virtual ThemeGeometryType ThemeGeometryTypeForWidget(nsIFrame* aFrame,
|
||||
uint8_t aWidgetType)
|
||||
{ return eThemeGeometryTypeUnknown; }
|
||||
|
||||
/**
|
||||
* Can the nsITheme implementation handle this widget?
|
||||
*/
|
||||
virtual bool ThemeSupportsWidget(nsPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType)=0;
|
||||
|
||||
virtual bool WidgetIsContainer(uint8_t aWidgetType)=0;
|
||||
|
||||
/**
|
||||
* Does the nsITheme implementation draw its own focus ring for this widget?
|
||||
*/
|
||||
virtual bool ThemeDrawsFocusForWidget(uint8_t aWidgetType)=0;
|
||||
|
||||
/**
|
||||
* Should we insert a dropmarker inside of combobox button?
|
||||
*/
|
||||
virtual bool ThemeNeedsComboboxDropmarker()=0;
|
||||
|
||||
/**
|
||||
* Should we hide scrollbars?
|
||||
*/
|
||||
virtual bool ShouldHideScrollbars()
|
||||
{ return false; }
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsITheme, NS_ITHEME_IID)
|
||||
|
||||
// Creator function
|
||||
extern nsresult NS_NewNativeTheme(nsISupports *aOuter, REFNSIID aIID, void **aResult);
|
||||
|
||||
#endif
|
||||
26
gfx/src/nsMargin.h
Normal file
26
gfx/src/nsMargin.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/* -*- 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 NSMARGIN_H
|
||||
#define NSMARGIN_H
|
||||
|
||||
#include "nsCoord.h"
|
||||
#include "nsPoint.h"
|
||||
#include "mozilla/gfx/BaseMargin.h"
|
||||
#include "mozilla/gfx/Rect.h"
|
||||
|
||||
struct nsMargin : public mozilla::gfx::BaseMargin<nscoord, nsMargin> {
|
||||
typedef mozilla::gfx::BaseMargin<nscoord, nsMargin> Super;
|
||||
|
||||
// Constructors
|
||||
nsMargin() : Super() {}
|
||||
nsMargin(const nsMargin& aMargin) : Super(aMargin) {}
|
||||
nsMargin(nscoord aTop, nscoord aRight, nscoord aBottom, nscoord aLeft)
|
||||
: Super(aTop, aRight, aBottom, aLeft) {}
|
||||
};
|
||||
|
||||
typedef mozilla::gfx::IntMargin nsIntMargin;
|
||||
|
||||
#endif /* NSMARGIN_H */
|
||||
106
gfx/src/nsPoint.h
Normal file
106
gfx/src/nsPoint.h
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/* -*- 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 NSPOINT_H
|
||||
#define NSPOINT_H
|
||||
|
||||
#include "nsCoord.h"
|
||||
#include "mozilla/gfx/BaseSize.h"
|
||||
#include "mozilla/gfx/BasePoint.h"
|
||||
#include "nsSize.h"
|
||||
#include "mozilla/gfx/Point.h"
|
||||
|
||||
// nsIntPoint represents a point in one of the types of pixels.
|
||||
// Uses of nsIntPoint should eventually be converted to CSSIntPoint,
|
||||
// LayoutDeviceIntPoint, etc. (see layout/base/Units.h).
|
||||
typedef mozilla::gfx::IntPoint nsIntPoint;
|
||||
|
||||
// nsPoint represents a point in app units.
|
||||
|
||||
struct nsPoint : public mozilla::gfx::BasePoint<nscoord, nsPoint> {
|
||||
typedef mozilla::gfx::BasePoint<nscoord, nsPoint> Super;
|
||||
|
||||
nsPoint() : Super() {}
|
||||
nsPoint(const nsPoint& aPoint) : Super(aPoint) {}
|
||||
nsPoint(nscoord aX, nscoord aY) : Super(aX, aY) {}
|
||||
|
||||
inline nsIntPoint ScaleToNearestPixels(float aXScale, float aYScale,
|
||||
nscoord aAppUnitsPerPixel) const;
|
||||
inline nsIntPoint ToNearestPixels(nscoord aAppUnitsPerPixel) const;
|
||||
|
||||
/**
|
||||
* Return this point scaled to a different appunits per pixel (APP) ratio.
|
||||
* @param aFromAPP the APP to scale from
|
||||
* @param aToAPP the APP to scale to
|
||||
*/
|
||||
MOZ_MUST_USE inline nsPoint
|
||||
ScaleToOtherAppUnits(int32_t aFromAPP, int32_t aToAPP) const;
|
||||
|
||||
MOZ_MUST_USE inline nsPoint
|
||||
RemoveResolution(const float resolution) const;
|
||||
MOZ_MUST_USE inline nsPoint
|
||||
ApplyResolution(const float resolution) const;
|
||||
};
|
||||
|
||||
inline nsPoint ToAppUnits(const nsIntPoint& aPoint, nscoord aAppUnitsPerPixel);
|
||||
|
||||
inline nsIntPoint
|
||||
nsPoint::ScaleToNearestPixels(float aXScale, float aYScale,
|
||||
nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
return nsIntPoint(
|
||||
NSToIntRoundUp(NSAppUnitsToDoublePixels(x, aAppUnitsPerPixel) * aXScale),
|
||||
NSToIntRoundUp(NSAppUnitsToDoublePixels(y, aAppUnitsPerPixel) * aYScale));
|
||||
}
|
||||
|
||||
inline nsIntPoint
|
||||
nsPoint::ToNearestPixels(nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
return ScaleToNearestPixels(1.0f, 1.0f, aAppUnitsPerPixel);
|
||||
}
|
||||
|
||||
inline nsPoint
|
||||
nsPoint::ScaleToOtherAppUnits(int32_t aFromAPP, int32_t aToAPP) const
|
||||
{
|
||||
if (aFromAPP != aToAPP) {
|
||||
nsPoint point;
|
||||
point.x = NSToCoordRound(NSCoordScale(x, aFromAPP, aToAPP));
|
||||
point.y = NSToCoordRound(NSCoordScale(y, aFromAPP, aToAPP));
|
||||
return point;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline nsPoint
|
||||
nsPoint::RemoveResolution(const float resolution) const {
|
||||
if (resolution != 1.0f) {
|
||||
nsPoint point;
|
||||
point.x = NSToCoordRound(NSCoordToFloat(x) / resolution);
|
||||
point.y = NSToCoordRound(NSCoordToFloat(y) / resolution);
|
||||
return point;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline nsPoint
|
||||
nsPoint::ApplyResolution(const float resolution) const {
|
||||
if (resolution != 1.0f) {
|
||||
nsPoint point;
|
||||
point.x = NSToCoordRound(NSCoordToFloat(x) * resolution);
|
||||
point.y = NSToCoordRound(NSCoordToFloat(y) * resolution);
|
||||
return point;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// app units are integer multiples of pixels, so no rounding needed
|
||||
inline nsPoint
|
||||
ToAppUnits(const nsIntPoint& aPoint, nscoord aAppUnitsPerPixel)
|
||||
{
|
||||
return nsPoint(NSIntPixelsToAppUnits(aPoint.x, aAppUnitsPerPixel),
|
||||
NSIntPixelsToAppUnits(aPoint.y, aAppUnitsPerPixel));
|
||||
}
|
||||
|
||||
#endif /* NSPOINT_H */
|
||||
62
gfx/src/nsRect.cpp
Normal file
62
gfx/src/nsRect.cpp
Normal 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/. */
|
||||
|
||||
#include "nsRect.h"
|
||||
#include "mozilla/gfx/Types.h" // for NS_SIDE_BOTTOM, etc
|
||||
#include "mozilla/CheckedInt.h" // for CheckedInt
|
||||
#include "nsDeviceContext.h" // for nsDeviceContext
|
||||
#include "nsString.h" // for nsAutoString, etc
|
||||
#include "nsMargin.h" // for nsMargin
|
||||
|
||||
static_assert((int(NS_SIDE_TOP) == 0) &&
|
||||
(int(NS_SIDE_RIGHT) == 1) &&
|
||||
(int(NS_SIDE_BOTTOM) == 2) &&
|
||||
(int(NS_SIDE_LEFT) == 3),
|
||||
"The mozilla::css::Side sequence must match the nsMargin nscoord sequence");
|
||||
|
||||
const mozilla::gfx::IntRect& GetMaxSizedIntRect() {
|
||||
static const mozilla::gfx::IntRect r(0, 0, INT32_MAX, INT32_MAX);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
bool nsRect::Overflows() const {
|
||||
#ifdef NS_COORD_IS_FLOAT
|
||||
return false;
|
||||
#else
|
||||
mozilla::CheckedInt<int32_t> xMost = this->x;
|
||||
xMost += this->width;
|
||||
mozilla::CheckedInt<int32_t> yMost = this->y;
|
||||
yMost += this->height;
|
||||
return !xMost.isValid() || !yMost.isValid();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Diagnostics
|
||||
|
||||
FILE* operator<<(FILE* out, const nsRect& rect)
|
||||
{
|
||||
nsAutoString tmp;
|
||||
|
||||
// Output the coordinates in fractional pixels so they're easier to read
|
||||
tmp.Append('{');
|
||||
tmp.AppendFloat(NSAppUnitsToFloatPixels(rect.x,
|
||||
nsDeviceContext::AppUnitsPerCSSPixel()));
|
||||
tmp.AppendLiteral(", ");
|
||||
tmp.AppendFloat(NSAppUnitsToFloatPixels(rect.y,
|
||||
nsDeviceContext::AppUnitsPerCSSPixel()));
|
||||
tmp.AppendLiteral(", ");
|
||||
tmp.AppendFloat(NSAppUnitsToFloatPixels(rect.width,
|
||||
nsDeviceContext::AppUnitsPerCSSPixel()));
|
||||
tmp.AppendLiteral(", ");
|
||||
tmp.AppendFloat(NSAppUnitsToFloatPixels(rect.height,
|
||||
nsDeviceContext::AppUnitsPerCSSPixel()));
|
||||
tmp.Append('}');
|
||||
fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
324
gfx/src/nsRect.h
Normal file
324
gfx/src/nsRect.h
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
/* -*- 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 NSRECT_H
|
||||
#define NSRECT_H
|
||||
|
||||
#include <stdio.h> // for FILE
|
||||
#include <stdint.h> // for int32_t, int64_t
|
||||
#include <algorithm> // for min/max
|
||||
#include "mozilla/Likely.h" // for MOZ_UNLIKELY
|
||||
#include "mozilla/gfx/Rect.h"
|
||||
#include "nsCoord.h" // for nscoord, etc
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "nsPoint.h" // for nsIntPoint, nsPoint
|
||||
#include "nsMargin.h" // for nsIntMargin, nsMargin
|
||||
#include "nsSize.h" // for IntSize, nsSize
|
||||
#include "nscore.h" // for NS_BUILD_REFCNT_LOGGING
|
||||
|
||||
typedef mozilla::gfx::IntRect nsIntRect;
|
||||
|
||||
struct nsRect :
|
||||
public mozilla::gfx::BaseRect<nscoord, nsRect, nsPoint, nsSize, nsMargin> {
|
||||
typedef mozilla::gfx::BaseRect<nscoord, nsRect, nsPoint, nsSize, nsMargin> Super;
|
||||
|
||||
static void VERIFY_COORD(nscoord aValue) { ::VERIFY_COORD(aValue); }
|
||||
|
||||
// Constructors
|
||||
nsRect() : Super()
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsRect);
|
||||
}
|
||||
nsRect(const nsRect& aRect) : Super(aRect)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsRect);
|
||||
}
|
||||
nsRect(const nsPoint& aOrigin, const nsSize &aSize) : Super(aOrigin, aSize)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsRect);
|
||||
}
|
||||
nsRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) :
|
||||
Super(aX, aY, aWidth, aHeight)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsRect);
|
||||
}
|
||||
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
~nsRect() {
|
||||
MOZ_COUNT_DTOR(nsRect);
|
||||
}
|
||||
#endif
|
||||
|
||||
// We have saturating versions of all the Union methods. These avoid
|
||||
// overflowing nscoord values in the 'width' and 'height' fields by
|
||||
// clamping the width and height values to nscoord_MAX if necessary.
|
||||
|
||||
MOZ_MUST_USE nsRect SaturatingUnion(const nsRect& aRect) const
|
||||
{
|
||||
if (IsEmpty()) {
|
||||
return aRect;
|
||||
} else if (aRect.IsEmpty()) {
|
||||
return *static_cast<const nsRect*>(this);
|
||||
} else {
|
||||
return SaturatingUnionEdges(aRect);
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_MUST_USE nsRect SaturatingUnionEdges(const nsRect& aRect) const
|
||||
{
|
||||
#ifdef NS_COORD_IS_FLOAT
|
||||
return UnionEdges(aRect);
|
||||
#else
|
||||
nsRect result;
|
||||
result.x = std::min(aRect.x, x);
|
||||
int64_t w = std::max(int64_t(aRect.x) + aRect.width, int64_t(x) + width) - result.x;
|
||||
if (MOZ_UNLIKELY(w > nscoord_MAX)) {
|
||||
// Clamp huge negative x to nscoord_MIN / 2 and try again.
|
||||
result.x = std::max(result.x, nscoord_MIN / 2);
|
||||
w = std::max(int64_t(aRect.x) + aRect.width, int64_t(x) + width) - result.x;
|
||||
if (MOZ_UNLIKELY(w > nscoord_MAX)) {
|
||||
w = nscoord_MAX;
|
||||
}
|
||||
}
|
||||
result.width = nscoord(w);
|
||||
|
||||
result.y = std::min(aRect.y, y);
|
||||
int64_t h = std::max(int64_t(aRect.y) + aRect.height, int64_t(y) + height) - result.y;
|
||||
if (MOZ_UNLIKELY(h > nscoord_MAX)) {
|
||||
// Clamp huge negative y to nscoord_MIN / 2 and try again.
|
||||
result.y = std::max(result.y, nscoord_MIN / 2);
|
||||
h = std::max(int64_t(aRect.y) + aRect.height, int64_t(y) + height) - result.y;
|
||||
if (MOZ_UNLIKELY(h > nscoord_MAX)) {
|
||||
h = nscoord_MAX;
|
||||
}
|
||||
}
|
||||
result.height = nscoord(h);
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef NS_COORD_IS_FLOAT
|
||||
// Make all nsRect Union methods be saturating.
|
||||
MOZ_MUST_USE nsRect UnionEdges(const nsRect& aRect) const
|
||||
{
|
||||
return SaturatingUnionEdges(aRect);
|
||||
}
|
||||
void UnionRectEdges(const nsRect& aRect1, const nsRect& aRect2)
|
||||
{
|
||||
*this = aRect1.UnionEdges(aRect2);
|
||||
}
|
||||
MOZ_MUST_USE nsRect Union(const nsRect& aRect) const
|
||||
{
|
||||
return SaturatingUnion(aRect);
|
||||
}
|
||||
void UnionRect(const nsRect& aRect1, const nsRect& aRect2)
|
||||
{
|
||||
*this = aRect1.Union(aRect2);
|
||||
}
|
||||
#endif
|
||||
|
||||
void SaturatingUnionRect(const nsRect& aRect1, const nsRect& aRect2)
|
||||
{
|
||||
*this = aRect1.SaturatingUnion(aRect2);
|
||||
}
|
||||
void SaturatingUnionRectEdges(const nsRect& aRect1, const nsRect& aRect2)
|
||||
{
|
||||
*this = aRect1.SaturatingUnionEdges(aRect2);
|
||||
}
|
||||
|
||||
// Return whether this rect's right or bottom edge overflow int32.
|
||||
bool Overflows() const;
|
||||
|
||||
/**
|
||||
* Return this rect scaled to a different appunits per pixel (APP) ratio.
|
||||
* In the RoundOut version we make the rect the smallest rect containing the
|
||||
* unrounded result. In the RoundIn version we make the rect the largest rect
|
||||
* contained in the unrounded result.
|
||||
* @param aFromAPP the APP to scale from
|
||||
* @param aToAPP the APP to scale to
|
||||
* @note this can turn an empty rectangle into a non-empty rectangle
|
||||
*/
|
||||
MOZ_MUST_USE inline nsRect
|
||||
ScaleToOtherAppUnitsRoundOut(int32_t aFromAPP, int32_t aToAPP) const;
|
||||
MOZ_MUST_USE inline nsRect
|
||||
ScaleToOtherAppUnitsRoundIn(int32_t aFromAPP, int32_t aToAPP) const;
|
||||
|
||||
MOZ_MUST_USE inline mozilla::gfx::IntRect
|
||||
ScaleToNearestPixels(float aXScale, float aYScale,
|
||||
nscoord aAppUnitsPerPixel) const;
|
||||
|
||||
MOZ_MUST_USE inline mozilla::gfx::IntRect
|
||||
ToNearestPixels(nscoord aAppUnitsPerPixel) const;
|
||||
|
||||
// Note: this can turn an empty rectangle into a non-empty rectangle
|
||||
MOZ_MUST_USE inline mozilla::gfx::IntRect
|
||||
ScaleToOutsidePixels(float aXScale, float aYScale,
|
||||
nscoord aAppUnitsPerPixel) const;
|
||||
|
||||
// Note: this can turn an empty rectangle into a non-empty rectangle
|
||||
MOZ_MUST_USE inline mozilla::gfx::IntRect
|
||||
ToOutsidePixels(nscoord aAppUnitsPerPixel) const;
|
||||
|
||||
MOZ_MUST_USE inline mozilla::gfx::IntRect
|
||||
ScaleToInsidePixels(float aXScale, float aYScale,
|
||||
nscoord aAppUnitsPerPixel) const;
|
||||
|
||||
MOZ_MUST_USE inline mozilla::gfx::IntRect
|
||||
ToInsidePixels(nscoord aAppUnitsPerPixel) const;
|
||||
|
||||
// This is here only to keep IPDL-generated code happy. DO NOT USE.
|
||||
bool operator==(const nsRect& aRect) const
|
||||
{
|
||||
return IsEqualEdges(aRect);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE inline nsRect RemoveResolution(const float aResolution) const;
|
||||
};
|
||||
|
||||
/*
|
||||
* App Unit/Pixel conversions
|
||||
*/
|
||||
|
||||
inline nsRect
|
||||
nsRect::ScaleToOtherAppUnitsRoundOut(int32_t aFromAPP, int32_t aToAPP) const
|
||||
{
|
||||
if (aFromAPP == aToAPP) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsRect rect;
|
||||
nscoord right = NSToCoordCeil(NSCoordScale(XMost(), aFromAPP, aToAPP));
|
||||
nscoord bottom = NSToCoordCeil(NSCoordScale(YMost(), aFromAPP, aToAPP));
|
||||
rect.x = NSToCoordFloor(NSCoordScale(x, aFromAPP, aToAPP));
|
||||
rect.y = NSToCoordFloor(NSCoordScale(y, aFromAPP, aToAPP));
|
||||
rect.width = (right - rect.x);
|
||||
rect.height = (bottom - rect.y);
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
inline nsRect
|
||||
nsRect::ScaleToOtherAppUnitsRoundIn(int32_t aFromAPP, int32_t aToAPP) const
|
||||
{
|
||||
if (aFromAPP == aToAPP) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsRect rect;
|
||||
nscoord right = NSToCoordFloor(NSCoordScale(XMost(), aFromAPP, aToAPP));
|
||||
nscoord bottom = NSToCoordFloor(NSCoordScale(YMost(), aFromAPP, aToAPP));
|
||||
rect.x = NSToCoordCeil(NSCoordScale(x, aFromAPP, aToAPP));
|
||||
rect.y = NSToCoordCeil(NSCoordScale(y, aFromAPP, aToAPP));
|
||||
rect.width = (right - rect.x);
|
||||
rect.height = (bottom - rect.y);
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
// scale the rect but round to preserve centers
|
||||
inline mozilla::gfx::IntRect
|
||||
nsRect::ScaleToNearestPixels(float aXScale, float aYScale,
|
||||
nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
mozilla::gfx::IntRect rect;
|
||||
rect.x = NSToIntRoundUp(NSAppUnitsToDoublePixels(x, aAppUnitsPerPixel) * aXScale);
|
||||
rect.y = NSToIntRoundUp(NSAppUnitsToDoublePixels(y, aAppUnitsPerPixel) * aYScale);
|
||||
// Avoid negative widths and heights due to overflow
|
||||
rect.width = std::max(0, NSToIntRoundUp(NSAppUnitsToDoublePixels(XMost(),
|
||||
aAppUnitsPerPixel) * aXScale) - rect.x);
|
||||
rect.height = std::max(0, NSToIntRoundUp(NSAppUnitsToDoublePixels(YMost(),
|
||||
aAppUnitsPerPixel) * aYScale) - rect.y);
|
||||
return rect;
|
||||
}
|
||||
|
||||
// scale the rect but round to smallest containing rect
|
||||
inline mozilla::gfx::IntRect
|
||||
nsRect::ScaleToOutsidePixels(float aXScale, float aYScale,
|
||||
nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
mozilla::gfx::IntRect rect;
|
||||
rect.x = NSToIntFloor(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)) * aXScale);
|
||||
rect.y = NSToIntFloor(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)) * aYScale);
|
||||
// Avoid negative widths and heights due to overflow
|
||||
rect.width = std::max(0, NSToIntCeil(NSAppUnitsToFloatPixels(XMost(),
|
||||
float(aAppUnitsPerPixel)) * aXScale) - rect.x);
|
||||
rect.height = std::max(0, NSToIntCeil(NSAppUnitsToFloatPixels(YMost(),
|
||||
float(aAppUnitsPerPixel)) * aYScale) - rect.y);
|
||||
return rect;
|
||||
}
|
||||
|
||||
// scale the rect but round to largest contained rect
|
||||
inline mozilla::gfx::IntRect
|
||||
nsRect::ScaleToInsidePixels(float aXScale, float aYScale,
|
||||
nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
mozilla::gfx::IntRect rect;
|
||||
rect.x = NSToIntCeil(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)) * aXScale);
|
||||
rect.y = NSToIntCeil(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)) * aYScale);
|
||||
// Avoid negative widths and heights due to overflow
|
||||
rect.width = std::max(0, NSToIntFloor(NSAppUnitsToFloatPixels(XMost(),
|
||||
float(aAppUnitsPerPixel)) * aXScale) - rect.x);
|
||||
rect.height = std::max(0, NSToIntFloor(NSAppUnitsToFloatPixels(YMost(),
|
||||
float(aAppUnitsPerPixel)) * aYScale) - rect.y);
|
||||
return rect;
|
||||
}
|
||||
|
||||
inline mozilla::gfx::IntRect
|
||||
nsRect::ToNearestPixels(nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
return ScaleToNearestPixels(1.0f, 1.0f, aAppUnitsPerPixel);
|
||||
}
|
||||
|
||||
inline mozilla::gfx::IntRect
|
||||
nsRect::ToOutsidePixels(nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
return ScaleToOutsidePixels(1.0f, 1.0f, aAppUnitsPerPixel);
|
||||
}
|
||||
|
||||
inline mozilla::gfx::IntRect
|
||||
nsRect::ToInsidePixels(nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
return ScaleToInsidePixels(1.0f, 1.0f, aAppUnitsPerPixel);
|
||||
}
|
||||
|
||||
inline nsRect
|
||||
nsRect::RemoveResolution(const float aResolution) const
|
||||
{
|
||||
MOZ_ASSERT(aResolution > 0.0f);
|
||||
nsRect rect;
|
||||
rect.x = NSToCoordRound(NSCoordToFloat(x) / aResolution);
|
||||
rect.y = NSToCoordRound(NSCoordToFloat(y) / aResolution);
|
||||
// A 1x1 rect indicates we are just hit testing a point, so pass down a 1x1
|
||||
// rect as well instead of possibly rounding the width or height to zero.
|
||||
if (width == 1 && height == 1) {
|
||||
rect.width = rect.height = 1;
|
||||
} else {
|
||||
rect.width = NSToCoordCeil(NSCoordToFloat(width) / aResolution);
|
||||
rect.height = NSToCoordCeil(NSCoordToFloat(height) / aResolution);
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
const mozilla::gfx::IntRect& GetMaxSizedIntRect();
|
||||
|
||||
// app units are integer multiples of pixels, so no rounding needed
|
||||
template<class units>
|
||||
nsRect
|
||||
ToAppUnits(const mozilla::gfx::IntRectTyped<units>& aRect, nscoord aAppUnitsPerPixel)
|
||||
{
|
||||
return nsRect(NSIntPixelsToAppUnits(aRect.x, aAppUnitsPerPixel),
|
||||
NSIntPixelsToAppUnits(aRect.y, aAppUnitsPerPixel),
|
||||
NSIntPixelsToAppUnits(aRect.width, aAppUnitsPerPixel),
|
||||
NSIntPixelsToAppUnits(aRect.height, aAppUnitsPerPixel));
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Diagnostics
|
||||
extern FILE* operator<<(FILE* out, const nsRect& rect);
|
||||
#endif // DEBUG
|
||||
|
||||
#endif /* NSRECT_H */
|
||||
1146
gfx/src/nsRegion.cpp
Normal file
1146
gfx/src/nsRegion.cpp
Normal file
File diff suppressed because it is too large
Load diff
868
gfx/src/nsRegion.h
Normal file
868
gfx/src/nsRegion.h
Normal file
|
|
@ -0,0 +1,868 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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 nsRegion_h__
|
||||
#define nsRegion_h__
|
||||
|
||||
#include <stddef.h> // for size_t
|
||||
#include <stdint.h> // for uint32_t, uint64_t
|
||||
#include <sys/types.h> // for int32_t
|
||||
#include <ostream> // for std::ostream
|
||||
#include "nsCoord.h" // for nscoord
|
||||
#include "nsError.h" // for nsresult
|
||||
#include "nsPoint.h" // for nsIntPoint, nsPoint
|
||||
#include "nsRect.h" // for mozilla::gfx::IntRect, nsRect
|
||||
#include "nsMargin.h" // for nsIntMargin
|
||||
#include "nsRegionFwd.h" // for nsIntRegion
|
||||
#include "nsStringGlue.h" // for nsCString
|
||||
#include "xpcom-config.h" // for CPP_THROW_NEW
|
||||
#include "mozilla/ArrayView.h" // for ArrayView
|
||||
#include "mozilla/Move.h" // for mozilla::Move
|
||||
#include "mozilla/gfx/MatrixFwd.h" // for mozilla::gfx::Matrix4x4
|
||||
|
||||
#include "pixman.h"
|
||||
|
||||
/* For information on the internal representation look at pixman-region.c
|
||||
*
|
||||
* This replaces an older homebrew implementation of nsRegion. The
|
||||
* representation used here may use more rectangles than nsRegion however, the
|
||||
* representation is canonical. This means that there's no need for an
|
||||
* Optimize() method because for a paticular region there is only one
|
||||
* representation. This means that nsIntRegion will have more predictable
|
||||
* performance characteristics than the old nsRegion and should not become
|
||||
* degenerate.
|
||||
*
|
||||
* The pixman region code originates from X11 which has spread to a variety of
|
||||
* projects including Qt, Gtk, Wine. It should perform reasonably well.
|
||||
*/
|
||||
|
||||
enum class VisitSide {
|
||||
TOP,
|
||||
BOTTOM,
|
||||
LEFT,
|
||||
RIGHT
|
||||
};
|
||||
|
||||
class nsRegion
|
||||
{
|
||||
public:
|
||||
typedef nsRect RectType;
|
||||
typedef nsPoint PointType;
|
||||
typedef nsMargin MarginType;
|
||||
|
||||
nsRegion () { pixman_region32_init(&mImpl); }
|
||||
MOZ_IMPLICIT nsRegion (const nsRect& aRect) { pixman_region32_init_rect(&mImpl,
|
||||
aRect.x,
|
||||
aRect.y,
|
||||
aRect.width,
|
||||
aRect.height); }
|
||||
explicit nsRegion (mozilla::gfx::ArrayView<pixman_box32_t> aRects)
|
||||
{
|
||||
pixman_region32_init_rects(&mImpl, aRects.Data(), aRects.Length());
|
||||
}
|
||||
nsRegion (const nsRegion& aRegion) { pixman_region32_init(&mImpl); pixman_region32_copy(&mImpl,aRegion.Impl()); }
|
||||
nsRegion (nsRegion&& aRegion) { mImpl = aRegion.mImpl; pixman_region32_init(&aRegion.mImpl); }
|
||||
nsRegion& operator = (nsRegion&& aRegion) {
|
||||
pixman_region32_fini(&mImpl);
|
||||
mImpl = aRegion.mImpl;
|
||||
pixman_region32_init(&aRegion.mImpl);
|
||||
return *this;
|
||||
}
|
||||
~nsRegion () { pixman_region32_fini(&mImpl); }
|
||||
nsRegion& operator = (const nsRect& aRect) { Copy (aRect); return *this; }
|
||||
nsRegion& operator = (const nsRegion& aRegion) { Copy (aRegion); return *this; }
|
||||
bool operator==(const nsRegion& aRgn) const
|
||||
{
|
||||
return IsEqual(aRgn);
|
||||
}
|
||||
bool operator!=(const nsRegion& aRgn) const
|
||||
{
|
||||
return !(*this == aRgn);
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const nsRegion& m);
|
||||
|
||||
void Swap(nsRegion* aOther)
|
||||
{
|
||||
pixman_region32_t tmp = mImpl;
|
||||
mImpl = aOther->mImpl;
|
||||
aOther->mImpl = tmp;
|
||||
}
|
||||
|
||||
static
|
||||
nsresult InitStatic()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static
|
||||
void ShutdownStatic() {}
|
||||
|
||||
void AndWith(const nsRegion& aOther)
|
||||
{
|
||||
And(*this, aOther);
|
||||
}
|
||||
void AndWith(const nsRect& aOther)
|
||||
{
|
||||
And(*this, aOther);
|
||||
}
|
||||
nsRegion& And(const nsRegion& aRgn1, const nsRegion& aRgn2)
|
||||
{
|
||||
pixman_region32_intersect(&mImpl, aRgn1.Impl(), aRgn2.Impl());
|
||||
return *this;
|
||||
}
|
||||
nsRegion& And(const nsRect& aRect, const nsRegion& aRegion)
|
||||
{
|
||||
return And(aRegion, aRect);
|
||||
}
|
||||
nsRegion& And(const nsRegion& aRegion, const nsRect& aRect)
|
||||
{
|
||||
pixman_region32_intersect_rect(&mImpl, aRegion.Impl(), aRect.x, aRect.y, aRect.width, aRect.height);
|
||||
return *this;
|
||||
}
|
||||
nsRegion& And(const nsRect& aRect1, const nsRect& aRect2)
|
||||
{
|
||||
nsRect TmpRect;
|
||||
|
||||
TmpRect.IntersectRect(aRect1, aRect2);
|
||||
return Copy(TmpRect);
|
||||
}
|
||||
|
||||
nsRegion& OrWith(const nsRegion& aOther)
|
||||
{
|
||||
return Or(*this, aOther);
|
||||
}
|
||||
nsRegion& OrWith(const nsRect& aOther)
|
||||
{
|
||||
return Or(*this, aOther);
|
||||
}
|
||||
nsRegion& Or(const nsRegion& aRgn1, const nsRegion& aRgn2)
|
||||
{
|
||||
pixman_region32_union(&mImpl, aRgn1.Impl(), aRgn2.Impl());
|
||||
return *this;
|
||||
}
|
||||
nsRegion& Or(const nsRegion& aRegion, const nsRect& aRect)
|
||||
{
|
||||
pixman_region32_union_rect(&mImpl, aRegion.Impl(), aRect.x, aRect.y, aRect.width, aRect.height);
|
||||
return *this;
|
||||
}
|
||||
nsRegion& Or(const nsRect& aRect, const nsRegion& aRegion)
|
||||
{
|
||||
return Or(aRegion, aRect);
|
||||
}
|
||||
nsRegion& Or(const nsRect& aRect1, const nsRect& aRect2)
|
||||
{
|
||||
Copy (aRect1);
|
||||
return Or (*this, aRect2);
|
||||
}
|
||||
|
||||
nsRegion& XorWith(const nsRegion& aOther)
|
||||
{
|
||||
return Xor(*this, aOther);
|
||||
}
|
||||
nsRegion& XorWith(const nsRect& aOther)
|
||||
{
|
||||
return Xor(*this, aOther);
|
||||
}
|
||||
nsRegion& Xor(const nsRegion& aRgn1, const nsRegion& aRgn2)
|
||||
{
|
||||
// this could be implemented better if pixman had direct
|
||||
// support for xoring regions.
|
||||
nsRegion p;
|
||||
p.Sub(aRgn1, aRgn2);
|
||||
nsRegion q;
|
||||
q.Sub(aRgn2, aRgn1);
|
||||
return Or(p, q);
|
||||
}
|
||||
nsRegion& Xor(const nsRegion& aRegion, const nsRect& aRect)
|
||||
{
|
||||
return Xor(aRegion, nsRegion(aRect));
|
||||
}
|
||||
nsRegion& Xor(const nsRect& aRect, const nsRegion& aRegion)
|
||||
{
|
||||
return Xor(nsRegion(aRect), aRegion);
|
||||
}
|
||||
nsRegion& Xor(const nsRect& aRect1, const nsRect& aRect2)
|
||||
{
|
||||
return Xor(nsRegion(aRect1), nsRegion(aRect2));
|
||||
}
|
||||
|
||||
nsRegion ToAppUnits (nscoord aAppUnitsPerPixel) const;
|
||||
|
||||
nsRegion& SubOut(const nsRegion& aOther)
|
||||
{
|
||||
return Sub(*this, aOther);
|
||||
}
|
||||
nsRegion& SubOut(const nsRect& aOther)
|
||||
{
|
||||
return Sub(*this, aOther);
|
||||
}
|
||||
nsRegion& Sub(const nsRegion& aRgn1, const nsRegion& aRgn2)
|
||||
{
|
||||
pixman_region32_subtract(&mImpl, aRgn1.Impl(), aRgn2.Impl());
|
||||
return *this;
|
||||
}
|
||||
nsRegion& Sub(const nsRegion& aRegion, const nsRect& aRect)
|
||||
{
|
||||
return Sub(aRegion, nsRegion(aRect));
|
||||
}
|
||||
nsRegion& Sub(const nsRect& aRect, const nsRegion& aRegion)
|
||||
{
|
||||
return Sub(nsRegion(aRect), aRegion);
|
||||
}
|
||||
nsRegion& Sub(const nsRect& aRect1, const nsRect& aRect2)
|
||||
{
|
||||
Copy(aRect1);
|
||||
return Sub(*this, aRect2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff the given point is inside the region. A region
|
||||
* created from a rect (x=0, y=0, w=100, h=100) will NOT contain
|
||||
* the point x=100, y=100.
|
||||
*/
|
||||
bool Contains (int aX, int aY) const
|
||||
{
|
||||
return pixman_region32_contains_point(Impl(), aX, aY, nullptr);
|
||||
}
|
||||
bool Contains (const nsRect& aRect) const
|
||||
{
|
||||
pixman_box32_t box = RectToBox(aRect);
|
||||
return pixman_region32_contains_rectangle(Impl(), &box) == PIXMAN_REGION_IN;
|
||||
}
|
||||
bool Contains (const nsRegion& aRgn) const;
|
||||
bool Intersects (const nsRect& aRect) const;
|
||||
|
||||
void MoveBy (int32_t aXOffset, int32_t aYOffset)
|
||||
{
|
||||
MoveBy (nsPoint (aXOffset, aYOffset));
|
||||
}
|
||||
void MoveBy (nsPoint aPt) { pixman_region32_translate(&mImpl, aPt.x, aPt.y); }
|
||||
void SetEmpty ()
|
||||
{
|
||||
pixman_region32_clear(&mImpl);
|
||||
}
|
||||
|
||||
nsRegion MovedBy(int32_t aXOffset, int32_t aYOffset) const
|
||||
{
|
||||
return MovedBy(nsPoint(aXOffset, aYOffset));
|
||||
}
|
||||
nsRegion MovedBy(const nsPoint& aPt) const
|
||||
{
|
||||
nsRegion copy(*this);
|
||||
copy.MoveBy(aPt);
|
||||
return copy;
|
||||
}
|
||||
|
||||
nsRegion Intersect(const nsRegion& aOther) const
|
||||
{
|
||||
nsRegion intersection;
|
||||
intersection.And(*this, aOther);
|
||||
return intersection;
|
||||
}
|
||||
|
||||
void Inflate(const nsMargin& aMargin);
|
||||
|
||||
nsRegion Inflated(const nsMargin& aMargin) const
|
||||
{
|
||||
nsRegion copy(*this);
|
||||
copy.Inflate(aMargin);
|
||||
return copy;
|
||||
}
|
||||
|
||||
bool IsEmpty () const { return !pixman_region32_not_empty(Impl()); }
|
||||
bool IsComplex () const { return GetNumRects() > 1; }
|
||||
bool IsEqual (const nsRegion& aRegion) const
|
||||
{
|
||||
return pixman_region32_equal(Impl(), aRegion.Impl());
|
||||
}
|
||||
uint32_t GetNumRects () const
|
||||
{
|
||||
// Work around pixman bug. Sometimes pixman creates regions with 1 rect
|
||||
// that's empty.
|
||||
uint32_t result = pixman_region32_n_rects(Impl());
|
||||
return (result == 1 && GetBounds().IsEmpty()) ? 0 : result;
|
||||
}
|
||||
const nsRect GetBounds () const { return BoxToRect(mImpl.extents); }
|
||||
uint64_t Area () const;
|
||||
|
||||
/**
|
||||
* Return this region scaled to a different appunits per pixel (APP) ratio.
|
||||
* This applies nsRect::ScaleToOtherAppUnitsRoundOut/In to each rect of the region.
|
||||
* @param aFromAPP the APP to scale from
|
||||
* @param aToAPP the APP to scale to
|
||||
* @note this can turn an empty region into a non-empty region
|
||||
*/
|
||||
MOZ_MUST_USE nsRegion
|
||||
ScaleToOtherAppUnitsRoundOut (int32_t aFromAPP, int32_t aToAPP) const;
|
||||
MOZ_MUST_USE nsRegion
|
||||
ScaleToOtherAppUnitsRoundIn (int32_t aFromAPP, int32_t aToAPP) const;
|
||||
nsRegion& ScaleRoundOut(float aXScale, float aYScale);
|
||||
nsRegion& ScaleInverseRoundOut(float aXScale, float aYScale);
|
||||
nsRegion& Transform (const mozilla::gfx::Matrix4x4 &aTransform);
|
||||
nsIntRegion ScaleToOutsidePixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
|
||||
nsIntRegion ScaleToInsidePixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
|
||||
nsIntRegion ScaleToNearestPixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
|
||||
nsIntRegion ToOutsidePixels (nscoord aAppUnitsPerPixel) const;
|
||||
nsIntRegion ToNearestPixels (nscoord aAppUnitsPerPixel) const;
|
||||
|
||||
/**
|
||||
* Gets the largest rectangle contained in the region.
|
||||
* @param aContainingRect if non-empty, we choose a rectangle that
|
||||
* maximizes the area intersecting with aContainingRect (and break ties by
|
||||
* then choosing the largest rectangle overall)
|
||||
*/
|
||||
nsRect GetLargestRectangle (const nsRect& aContainingRect = nsRect()) const;
|
||||
|
||||
/**
|
||||
* Make sure the region has at most aMaxRects by adding area to it
|
||||
* if necessary. The simplified region will be a superset of the
|
||||
* original region. The simplified region's bounding box will be
|
||||
* the same as for the current region.
|
||||
*/
|
||||
void SimplifyOutward (uint32_t aMaxRects);
|
||||
/**
|
||||
* Simplify the region by adding at most aThreshold area between spans of
|
||||
* rects. The simplified region will be a superset of the original region.
|
||||
* The simplified region's bounding box will be the same as for the current
|
||||
* region.
|
||||
*/
|
||||
void SimplifyOutwardByArea(uint32_t aThreshold);
|
||||
/**
|
||||
* Make sure the region has at most aMaxRects by removing area from
|
||||
* it if necessary. The simplified region will be a subset of the
|
||||
* original region.
|
||||
*/
|
||||
void SimplifyInward (uint32_t aMaxRects);
|
||||
|
||||
/**
|
||||
* VisitEdges is a weird kind of function that we use for padding
|
||||
* out surfaces to prevent texture filtering artifacts.
|
||||
* It calls the visitFn callback for each of the exterior edges of
|
||||
* the regions. The top and bottom edges will be expanded 1 pixel
|
||||
* to the left and right if there's an outside corner. The order
|
||||
* the edges are visited is not guaranteed.
|
||||
*
|
||||
* visitFn has a side parameter that can be TOP,BOTTOM,LEFT,RIGHT
|
||||
* and specifies which kind of edge is being visited. x1, y1, x2, y2
|
||||
* are the coordinates of the line. (x1 == x2) || (y1 == y2)
|
||||
*/
|
||||
typedef void (*visitFn)(void *closure, VisitSide side, int x1, int y1, int x2, int y2);
|
||||
void VisitEdges(visitFn, void *closure);
|
||||
|
||||
nsCString ToString() const;
|
||||
|
||||
class RectIterator
|
||||
{
|
||||
int mCurrent; // Index of the current entry
|
||||
int mLimit; // Index one past the final entry.
|
||||
mutable nsRect mTmp; // The most recently gotten rectangle.
|
||||
pixman_box32_t *mBoxes;
|
||||
|
||||
public:
|
||||
explicit RectIterator(const nsRegion& aRegion)
|
||||
{
|
||||
mCurrent = 0;
|
||||
mBoxes = pixman_region32_rectangles(aRegion.Impl(), &mLimit);
|
||||
// Work around pixman bug. Sometimes pixman creates regions with 1 rect
|
||||
// that's empty.
|
||||
if (mLimit == 1 && nsRegion::BoxToRect(mBoxes[0]).IsEmpty()) {
|
||||
mLimit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool Done() const { return mCurrent == mLimit; }
|
||||
|
||||
const nsRect& Get() const
|
||||
{
|
||||
MOZ_ASSERT(!Done());
|
||||
mTmp = nsRegion::BoxToRect(mBoxes[mCurrent]);
|
||||
NS_ASSERTION(!mTmp.IsEmpty(), "Shouldn't return empty rect");
|
||||
return mTmp;
|
||||
}
|
||||
|
||||
void Next()
|
||||
{
|
||||
MOZ_ASSERT(!Done());
|
||||
mCurrent++;
|
||||
}
|
||||
};
|
||||
|
||||
RectIterator RectIter() const { return RectIterator(*this); }
|
||||
|
||||
private:
|
||||
pixman_region32_t mImpl;
|
||||
|
||||
#ifndef MOZ_TREE_PIXMAN
|
||||
// For compatibility with pixman versions older than 0.25.2.
|
||||
static inline void
|
||||
pixman_region32_clear(pixman_region32_t *region)
|
||||
{
|
||||
pixman_region32_fini(region);
|
||||
pixman_region32_init(region);
|
||||
}
|
||||
#endif
|
||||
|
||||
nsIntRegion ToPixels(nscoord aAppUnitsPerPixel, bool aOutsidePixels) const;
|
||||
|
||||
nsRegion& Copy (const nsRegion& aRegion)
|
||||
{
|
||||
pixman_region32_copy(&mImpl, aRegion.Impl());
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsRegion& Copy (const nsRect& aRect)
|
||||
{
|
||||
// pixman needs to distinguish between an empty region and a region
|
||||
// with one rect so that it can return a different number of rectangles.
|
||||
// Empty rect: data = empty_box
|
||||
// 1 rect: data = null
|
||||
// >1 rect: data = rects
|
||||
if (aRect.IsEmpty()) {
|
||||
pixman_region32_clear(&mImpl);
|
||||
} else {
|
||||
pixman_box32_t box = RectToBox(aRect);
|
||||
pixman_region32_reset(&mImpl, &box);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
static inline pixman_box32_t RectToBox(const nsRect &aRect)
|
||||
{
|
||||
pixman_box32_t box = { aRect.x, aRect.y, aRect.XMost(), aRect.YMost() };
|
||||
return box;
|
||||
}
|
||||
|
||||
static inline pixman_box32_t RectToBox(const mozilla::gfx::IntRect &aRect)
|
||||
{
|
||||
pixman_box32_t box = { aRect.x, aRect.y, aRect.XMost(), aRect.YMost() };
|
||||
return box;
|
||||
}
|
||||
|
||||
|
||||
static inline nsRect BoxToRect(const pixman_box32_t &aBox)
|
||||
{
|
||||
return nsRect(aBox.x1, aBox.y1,
|
||||
aBox.x2 - aBox.x1,
|
||||
aBox.y2 - aBox.y1);
|
||||
}
|
||||
|
||||
pixman_region32_t* Impl() const
|
||||
{
|
||||
return const_cast<pixman_region32_t*>(&mImpl);
|
||||
}
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
/**
|
||||
* BaseIntRegions use int32_t coordinates.
|
||||
*/
|
||||
template <typename Derived, typename Rect, typename Point, typename Margin>
|
||||
class BaseIntRegion
|
||||
{
|
||||
friend class ::nsRegion;
|
||||
|
||||
// Give access to all specializations of IntRegionTyped, not just ones that
|
||||
// derive from this specialization of BaseIntRegion.
|
||||
template <typename units>
|
||||
friend class IntRegionTyped;
|
||||
|
||||
public:
|
||||
typedef Rect RectType;
|
||||
typedef Point PointType;
|
||||
typedef Margin MarginType;
|
||||
|
||||
BaseIntRegion () {}
|
||||
MOZ_IMPLICIT BaseIntRegion (const Rect& aRect) : mImpl (ToRect(aRect)) {}
|
||||
explicit BaseIntRegion (mozilla::gfx::ArrayView<pixman_box32_t> aRects) : mImpl (aRects) {}
|
||||
BaseIntRegion (const BaseIntRegion& aRegion) : mImpl (aRegion.mImpl) {}
|
||||
BaseIntRegion (BaseIntRegion&& aRegion) : mImpl (mozilla::Move(aRegion.mImpl)) {}
|
||||
Derived& operator = (const Rect& aRect) { mImpl = ToRect (aRect); return This(); }
|
||||
Derived& operator = (const Derived& aRegion) { mImpl = aRegion.mImpl; return This(); }
|
||||
Derived& operator = (Derived&& aRegion) { mImpl = mozilla::Move(aRegion.mImpl); return This(); }
|
||||
|
||||
bool operator==(const Derived& aRgn) const
|
||||
{
|
||||
return IsEqual(aRgn);
|
||||
}
|
||||
bool operator!=(const Derived& aRgn) const
|
||||
{
|
||||
return !(*this == aRgn);
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const Derived& m) {
|
||||
return stream << m.mImpl;
|
||||
}
|
||||
|
||||
void Swap(Derived* aOther)
|
||||
{
|
||||
mImpl.Swap(&aOther->mImpl);
|
||||
}
|
||||
|
||||
void AndWith(const Derived& aOther)
|
||||
{
|
||||
And(This(), aOther);
|
||||
}
|
||||
void AndWith(const Rect& aOther)
|
||||
{
|
||||
And(This(), aOther);
|
||||
}
|
||||
Derived& And (const Derived& aRgn1, const Derived& aRgn2)
|
||||
{
|
||||
mImpl.And (aRgn1.mImpl, aRgn2.mImpl);
|
||||
return This();
|
||||
}
|
||||
Derived& And (const Derived& aRegion, const Rect& aRect)
|
||||
{
|
||||
mImpl.And (aRegion.mImpl, ToRect (aRect));
|
||||
return This();
|
||||
}
|
||||
Derived& And (const Rect& aRect, const Derived& aRegion)
|
||||
{
|
||||
return And (aRegion, aRect);
|
||||
}
|
||||
Derived& And (const Rect& aRect1, const Rect& aRect2)
|
||||
{
|
||||
Rect TmpRect;
|
||||
|
||||
TmpRect.IntersectRect (aRect1, aRect2);
|
||||
mImpl = ToRect (TmpRect);
|
||||
return This();
|
||||
}
|
||||
|
||||
Derived& OrWith(const Derived& aOther)
|
||||
{
|
||||
return Or(This(), aOther);
|
||||
}
|
||||
Derived& OrWith(const Rect& aOther)
|
||||
{
|
||||
return Or(This(), aOther);
|
||||
}
|
||||
Derived& Or (const Derived& aRgn1, const Derived& aRgn2)
|
||||
{
|
||||
mImpl.Or (aRgn1.mImpl, aRgn2.mImpl);
|
||||
return This();
|
||||
}
|
||||
Derived& Or (const Derived& aRegion, const Rect& aRect)
|
||||
{
|
||||
mImpl.Or (aRegion.mImpl, ToRect (aRect));
|
||||
return This();
|
||||
}
|
||||
Derived& Or (const Rect& aRect, const Derived& aRegion)
|
||||
{
|
||||
return Or (aRegion, aRect);
|
||||
}
|
||||
Derived& Or (const Rect& aRect1, const Rect& aRect2)
|
||||
{
|
||||
mImpl = ToRect (aRect1);
|
||||
return Or (This(), aRect2);
|
||||
}
|
||||
|
||||
Derived& XorWith(const Derived& aOther)
|
||||
{
|
||||
return Xor(This(), aOther);
|
||||
}
|
||||
Derived& XorWith(const Rect& aOther)
|
||||
{
|
||||
return Xor(This(), aOther);
|
||||
}
|
||||
Derived& Xor (const Derived& aRgn1, const Derived& aRgn2)
|
||||
{
|
||||
mImpl.Xor (aRgn1.mImpl, aRgn2.mImpl);
|
||||
return This();
|
||||
}
|
||||
Derived& Xor (const Derived& aRegion, const Rect& aRect)
|
||||
{
|
||||
mImpl.Xor (aRegion.mImpl, ToRect (aRect));
|
||||
return This();
|
||||
}
|
||||
Derived& Xor (const Rect& aRect, const Derived& aRegion)
|
||||
{
|
||||
return Xor (aRegion, aRect);
|
||||
}
|
||||
Derived& Xor (const Rect& aRect1, const Rect& aRect2)
|
||||
{
|
||||
mImpl = ToRect (aRect1);
|
||||
return Xor (This(), aRect2);
|
||||
}
|
||||
|
||||
Derived& SubOut(const Derived& aOther)
|
||||
{
|
||||
return Sub(This(), aOther);
|
||||
}
|
||||
Derived& SubOut(const Rect& aOther)
|
||||
{
|
||||
return Sub(This(), aOther);
|
||||
}
|
||||
Derived& Sub (const Derived& aRgn1, const Derived& aRgn2)
|
||||
{
|
||||
mImpl.Sub (aRgn1.mImpl, aRgn2.mImpl);
|
||||
return This();
|
||||
}
|
||||
Derived& Sub (const Derived& aRegion, const Rect& aRect)
|
||||
{
|
||||
mImpl.Sub (aRegion.mImpl, ToRect (aRect));
|
||||
return This();
|
||||
}
|
||||
Derived& Sub (const Rect& aRect, const Derived& aRegion)
|
||||
{
|
||||
return Sub (Derived (aRect), aRegion);
|
||||
}
|
||||
Derived& Sub (const Rect& aRect1, const Rect& aRect2)
|
||||
{
|
||||
mImpl = ToRect (aRect1);
|
||||
return Sub (This(), aRect2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff the given point is inside the region. A region
|
||||
* created from a rect (x=0, y=0, w=100, h=100) will NOT contain
|
||||
* the point x=100, y=100.
|
||||
*/
|
||||
bool Contains (int aX, int aY) const
|
||||
{
|
||||
return mImpl.Contains(aX, aY);
|
||||
}
|
||||
bool Contains (const Rect& aRect) const
|
||||
{
|
||||
return mImpl.Contains (ToRect (aRect));
|
||||
}
|
||||
bool Contains (const Derived& aRgn) const
|
||||
{
|
||||
return mImpl.Contains (aRgn.mImpl);
|
||||
}
|
||||
bool Intersects (const Rect& aRect) const
|
||||
{
|
||||
return mImpl.Intersects (ToRect (aRect));
|
||||
}
|
||||
|
||||
void MoveBy (int32_t aXOffset, int32_t aYOffset)
|
||||
{
|
||||
MoveBy (Point (aXOffset, aYOffset));
|
||||
}
|
||||
void MoveBy (Point aPt)
|
||||
{
|
||||
mImpl.MoveBy (aPt.x, aPt.y);
|
||||
}
|
||||
Derived MovedBy(int32_t aXOffset, int32_t aYOffset) const
|
||||
{
|
||||
return MovedBy(Point(aXOffset, aYOffset));
|
||||
}
|
||||
Derived MovedBy(const Point& aPt) const
|
||||
{
|
||||
Derived copy(This());
|
||||
copy.MoveBy(aPt);
|
||||
return copy;
|
||||
}
|
||||
|
||||
Derived Intersect(const Derived& aOther) const
|
||||
{
|
||||
Derived intersection;
|
||||
intersection.And(This(), aOther);
|
||||
return intersection;
|
||||
}
|
||||
|
||||
void Inflate(const Margin& aMargin)
|
||||
{
|
||||
mImpl.Inflate(nsMargin(aMargin.top, aMargin.right, aMargin.bottom, aMargin.left));
|
||||
}
|
||||
Derived Inflated(const Margin& aMargin) const
|
||||
{
|
||||
Derived copy(This());
|
||||
copy.Inflate(aMargin);
|
||||
return copy;
|
||||
}
|
||||
|
||||
void SetEmpty ()
|
||||
{
|
||||
mImpl.SetEmpty ();
|
||||
}
|
||||
|
||||
bool IsEmpty () const { return mImpl.IsEmpty (); }
|
||||
bool IsComplex () const { return mImpl.IsComplex (); }
|
||||
bool IsEqual (const Derived& aRegion) const
|
||||
{
|
||||
return mImpl.IsEqual (aRegion.mImpl);
|
||||
}
|
||||
uint32_t GetNumRects () const { return mImpl.GetNumRects (); }
|
||||
Rect GetBounds () const { return FromRect (mImpl.GetBounds ()); }
|
||||
uint64_t Area () const { return mImpl.Area(); }
|
||||
nsRegion ToAppUnits (nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
nsRegion result;
|
||||
for (auto iter = RectIter(); !iter.Done(); iter.Next()) {
|
||||
nsRect appRect = ::ToAppUnits(iter.Get(), aAppUnitsPerPixel);
|
||||
result.Or(result, appRect);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
Rect GetLargestRectangle (const Rect& aContainingRect = Rect()) const
|
||||
{
|
||||
return FromRect (mImpl.GetLargestRectangle( ToRect(aContainingRect) ));
|
||||
}
|
||||
|
||||
Derived& ScaleRoundOut (float aXScale, float aYScale)
|
||||
{
|
||||
mImpl.ScaleRoundOut(aXScale, aYScale);
|
||||
return This();
|
||||
}
|
||||
|
||||
Derived& ScaleInverseRoundOut (float aXScale, float aYScale)
|
||||
{
|
||||
mImpl.ScaleInverseRoundOut(aXScale, aYScale);
|
||||
return This();
|
||||
}
|
||||
|
||||
// Prefer using TransformBy(matrix, region) from UnitTransforms.h,
|
||||
// as applying the transform should typically change the unit system.
|
||||
// TODO(botond): Move this to IntRegionTyped and disable it for
|
||||
// unit != UnknownUnits.
|
||||
Derived& Transform (const mozilla::gfx::Matrix4x4 &aTransform)
|
||||
{
|
||||
mImpl.Transform(aTransform);
|
||||
return This();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the region has at most aMaxRects by adding area to it
|
||||
* if necessary. The simplified region will be a superset of the
|
||||
* original region. The simplified region's bounding box will be
|
||||
* the same as for the current region.
|
||||
*/
|
||||
void SimplifyOutward (uint32_t aMaxRects)
|
||||
{
|
||||
mImpl.SimplifyOutward (aMaxRects);
|
||||
}
|
||||
void SimplifyOutwardByArea (uint32_t aThreshold)
|
||||
{
|
||||
mImpl.SimplifyOutwardByArea (aThreshold);
|
||||
}
|
||||
/**
|
||||
* Make sure the region has at most aMaxRects by removing area from
|
||||
* it if necessary. The simplified region will be a subset of the
|
||||
* original region.
|
||||
*/
|
||||
void SimplifyInward (uint32_t aMaxRects)
|
||||
{
|
||||
mImpl.SimplifyInward (aMaxRects);
|
||||
}
|
||||
|
||||
typedef void (*visitFn)(void *closure, VisitSide side, int x1, int y1, int x2, int y2);
|
||||
void VisitEdges (visitFn visit, void *closure)
|
||||
{
|
||||
mImpl.VisitEdges (visit, closure);
|
||||
}
|
||||
|
||||
nsCString ToString() const { return mImpl.ToString(); }
|
||||
|
||||
class RectIterator
|
||||
{
|
||||
nsRegion::RectIterator mImpl; // The underlying iterator.
|
||||
mutable Rect mTmp; // The most recently gotten rectangle.
|
||||
|
||||
public:
|
||||
explicit RectIterator(const BaseIntRegion& aRegion)
|
||||
: mImpl(aRegion.mImpl)
|
||||
{}
|
||||
|
||||
bool Done() const { return mImpl.Done(); }
|
||||
|
||||
const Rect& Get() const
|
||||
{
|
||||
mTmp = FromRect(mImpl.Get());
|
||||
return mTmp;
|
||||
}
|
||||
|
||||
void Next() { mImpl.Next(); }
|
||||
};
|
||||
|
||||
RectIterator RectIter() const { return RectIterator(*this); }
|
||||
|
||||
protected:
|
||||
// Expose enough to derived classes from them to define conversions
|
||||
// between different types of BaseIntRegions.
|
||||
explicit BaseIntRegion(const nsRegion& aImpl) : mImpl(aImpl) {}
|
||||
const nsRegion& Impl() const { return mImpl; }
|
||||
private:
|
||||
nsRegion mImpl;
|
||||
|
||||
static nsRect ToRect(const Rect& aRect)
|
||||
{
|
||||
return nsRect (aRect.x, aRect.y, aRect.width, aRect.height);
|
||||
}
|
||||
static Rect FromRect(const nsRect& aRect)
|
||||
{
|
||||
return Rect (aRect.x, aRect.y, aRect.width, aRect.height);
|
||||
}
|
||||
|
||||
Derived& This()
|
||||
{
|
||||
return *static_cast<Derived*>(this);
|
||||
}
|
||||
const Derived& This() const
|
||||
{
|
||||
return *static_cast<const Derived*>(this);
|
||||
}
|
||||
};
|
||||
|
||||
template <class units>
|
||||
class IntRegionTyped :
|
||||
public BaseIntRegion<IntRegionTyped<units>, IntRectTyped<units>, IntPointTyped<units>, IntMarginTyped<units>>
|
||||
{
|
||||
typedef BaseIntRegion<IntRegionTyped<units>, IntRectTyped<units>, IntPointTyped<units>, IntMarginTyped<units>> Super;
|
||||
|
||||
// Make other specializations of IntRegionTyped friends.
|
||||
template <typename OtherUnits>
|
||||
friend class IntRegionTyped;
|
||||
|
||||
static_assert(IsPixel<units>::value, "'units' must be a coordinate system tag");
|
||||
|
||||
public:
|
||||
typedef IntRectTyped<units> RectType;
|
||||
typedef IntPointTyped<units> PointType;
|
||||
typedef IntMarginTyped<units> MarginType;
|
||||
|
||||
// Forward constructors.
|
||||
IntRegionTyped() {}
|
||||
MOZ_IMPLICIT IntRegionTyped(const IntRectTyped<units>& aRect) : Super(aRect) {}
|
||||
IntRegionTyped(const IntRegionTyped& aRegion) : Super(aRegion) {}
|
||||
explicit IntRegionTyped(mozilla::gfx::ArrayView<pixman_box32_t> aRects) : Super(aRects) {}
|
||||
IntRegionTyped(IntRegionTyped&& aRegion) : Super(mozilla::Move(aRegion)) {}
|
||||
|
||||
// Assignment operators need to be forwarded as well, otherwise the compiler
|
||||
// will declare deleted ones.
|
||||
IntRegionTyped& operator=(const IntRegionTyped& aRegion)
|
||||
{
|
||||
return Super::operator=(aRegion);
|
||||
}
|
||||
IntRegionTyped& operator=(IntRegionTyped&& aRegion)
|
||||
{
|
||||
return Super::operator=(mozilla::Move(aRegion));
|
||||
}
|
||||
|
||||
static IntRegionTyped FromUnknownRegion(const IntRegion& aRegion)
|
||||
{
|
||||
return IntRegionTyped(aRegion.Impl());
|
||||
}
|
||||
IntRegion ToUnknownRegion() const
|
||||
{
|
||||
// Need |this->| because Impl() is defined in a dependent base class.
|
||||
return IntRegion(this->Impl());
|
||||
}
|
||||
private:
|
||||
// This is deliberately private, so calling code uses FromUnknownRegion().
|
||||
explicit IntRegionTyped(const nsRegion& aRegion) : Super(aRegion) {}
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
typedef mozilla::gfx::IntRegion nsIntRegion;
|
||||
|
||||
#endif
|
||||
26
gfx/src/nsRegionFwd.h
Normal file
26
gfx/src/nsRegionFwd.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/* 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 nsRegionFwd_h__
|
||||
#define nsRegionFwd_h__
|
||||
|
||||
// Forward declare enough things to define the typedef |nsIntRegion|.
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
struct UnknownUnits;
|
||||
|
||||
template <class units>
|
||||
class IntRegionTyped;
|
||||
|
||||
typedef IntRegionTyped<UnknownUnits> IntRegion;
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
typedef mozilla::gfx::IntRegion nsIntRegion;
|
||||
|
||||
#endif
|
||||
41
gfx/src/nsRenderingContext.h
Normal file
41
gfx/src/nsRenderingContext.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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 NSRENDERINGCONTEXT__H__
|
||||
#define NSRENDERINGCONTEXT__H__
|
||||
|
||||
#include "gfxContext.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
class DrawTarget;
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
class MOZ_STACK_CLASS nsRenderingContext final
|
||||
{
|
||||
typedef mozilla::gfx::DrawTarget DrawTarget;
|
||||
|
||||
public:
|
||||
explicit nsRenderingContext(gfxContext* aThebesContext)
|
||||
: mThebes(aThebesContext)
|
||||
{}
|
||||
|
||||
explicit nsRenderingContext(already_AddRefed<gfxContext>&& aThebesContext)
|
||||
: mThebes(aThebesContext)
|
||||
{}
|
||||
|
||||
// These accessors will never return null.
|
||||
gfxContext *ThebesContext() { return mThebes; }
|
||||
DrawTarget *GetDrawTarget() { return mThebes->GetDrawTarget(); }
|
||||
|
||||
private:
|
||||
RefPtr<gfxContext> mThebes;
|
||||
};
|
||||
|
||||
#endif // NSRENDERINGCONTEXT__H__
|
||||
159
gfx/src/nsScriptableRegion.cpp
Normal file
159
gfx/src/nsScriptableRegion.cpp
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/* -*- 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 "nsScriptableRegion.h"
|
||||
#include <stdint.h> // for uint32_t
|
||||
#include <sys/types.h> // for int32_t
|
||||
#include "js/RootingAPI.h" // for Rooted
|
||||
#include "js/Value.h" // for INT_TO_JSVAL, etc
|
||||
#include "jsapi.h" // for JS_DefineElement, etc
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
|
||||
#include "nsError.h" // for NS_OK, NS_ERROR_FAILURE, etc
|
||||
#include "nsID.h"
|
||||
#include "nsRect.h" // for mozilla::gfx::IntRect
|
||||
#include "nscore.h" // for NS_IMETHODIMP
|
||||
|
||||
class JSObject;
|
||||
struct JSContext;
|
||||
|
||||
nsScriptableRegion::nsScriptableRegion()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsScriptableRegion, nsIScriptableRegion)
|
||||
|
||||
NS_IMETHODIMP nsScriptableRegion::Init()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsScriptableRegion::SetToRegion(nsIScriptableRegion *aRegion)
|
||||
{
|
||||
aRegion->GetRegion(&mRegion);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsScriptableRegion::SetToRect(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight)
|
||||
{
|
||||
mRegion = mozilla::gfx::IntRect(aX, aY, aWidth, aHeight);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsScriptableRegion::IntersectRegion(nsIScriptableRegion *aRegion)
|
||||
{
|
||||
nsIntRegion region;
|
||||
aRegion->GetRegion(®ion);
|
||||
mRegion.And(mRegion, region);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsScriptableRegion::IntersectRect(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight)
|
||||
{
|
||||
mRegion.And(mRegion, mozilla::gfx::IntRect(aX, aY, aWidth, aHeight));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsScriptableRegion::UnionRegion(nsIScriptableRegion *aRegion)
|
||||
{
|
||||
nsIntRegion region;
|
||||
aRegion->GetRegion(®ion);
|
||||
mRegion.Or(mRegion, region);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsScriptableRegion::UnionRect(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight)
|
||||
{
|
||||
mRegion.Or(mRegion, mozilla::gfx::IntRect(aX, aY, aWidth, aHeight));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsScriptableRegion::SubtractRegion(nsIScriptableRegion *aRegion)
|
||||
{
|
||||
nsIntRegion region;
|
||||
aRegion->GetRegion(®ion);
|
||||
mRegion.Sub(mRegion, region);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsScriptableRegion::SubtractRect(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight)
|
||||
{
|
||||
mRegion.Sub(mRegion, mozilla::gfx::IntRect(aX, aY, aWidth, aHeight));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsScriptableRegion::IsEmpty(bool *isEmpty)
|
||||
{
|
||||
*isEmpty = mRegion.IsEmpty();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsScriptableRegion::IsEqualRegion(nsIScriptableRegion *aRegion, bool *isEqual)
|
||||
{
|
||||
nsIntRegion region;
|
||||
aRegion->GetRegion(®ion);
|
||||
*isEqual = mRegion.IsEqual(region);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsScriptableRegion::GetBoundingBox(int32_t *aX, int32_t *aY, int32_t *aWidth, int32_t *aHeight)
|
||||
{
|
||||
mozilla::gfx::IntRect boundRect = mRegion.GetBounds();
|
||||
*aX = boundRect.x;
|
||||
*aY = boundRect.y;
|
||||
*aWidth = boundRect.width;
|
||||
*aHeight = boundRect.height;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsScriptableRegion::Offset(int32_t aXOffset, int32_t aYOffset)
|
||||
{
|
||||
mRegion.MoveBy(aXOffset, aYOffset);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsScriptableRegion::ContainsRect(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight, bool *containsRect)
|
||||
{
|
||||
*containsRect = mRegion.Contains(mozilla::gfx::IntRect(aX, aY, aWidth, aHeight));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsScriptableRegion::GetRegion(nsIntRegion* outRgn)
|
||||
{
|
||||
*outRgn = mRegion;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsScriptableRegion::GetRects(JSContext* aCx, JS::MutableHandle<JS::Value> aRects)
|
||||
{
|
||||
uint32_t numRects = mRegion.GetNumRects();
|
||||
|
||||
if (!numRects) {
|
||||
aRects.setNull();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> destArray(aCx, JS_NewArrayObject(aCx, numRects * 4));
|
||||
if (!destArray) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
aRects.setObject(*destArray);
|
||||
|
||||
uint32_t n = 0;
|
||||
for (auto iter = mRegion.RectIter(); !iter.Done(); iter.Next()) {
|
||||
const mozilla::gfx::IntRect& rect = iter.Get();
|
||||
if (!JS_DefineElement(aCx, destArray, n, rect.x, JSPROP_ENUMERATE) ||
|
||||
!JS_DefineElement(aCx, destArray, n + 1, rect.y, JSPROP_ENUMERATE) ||
|
||||
!JS_DefineElement(aCx, destArray, n + 2, rect.width, JSPROP_ENUMERATE) ||
|
||||
!JS_DefineElement(aCx, destArray, n + 3, rect.height, JSPROP_ENUMERATE)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
n += 4;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
28
gfx/src/nsScriptableRegion.h
Normal file
28
gfx/src/nsScriptableRegion.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/* -*- Mode: IDL; 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 nsScriptableRegion_h
|
||||
#define nsScriptableRegion_h
|
||||
|
||||
#include "nsIScriptableRegion.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsRegion.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsScriptableRegion final : public nsIScriptableRegion {
|
||||
public:
|
||||
nsScriptableRegion();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_DECL_NSISCRIPTABLEREGION
|
||||
|
||||
private:
|
||||
~nsScriptableRegion() {}
|
||||
nsIntRegion mRegion;
|
||||
};
|
||||
|
||||
#endif
|
||||
70
gfx/src/nsSize.h
Normal file
70
gfx/src/nsSize.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/* -*- 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 NSSIZE_H
|
||||
#define NSSIZE_H
|
||||
|
||||
#include "nsCoord.h"
|
||||
#include "mozilla/gfx/BaseSize.h"
|
||||
#include "mozilla/gfx/Point.h"
|
||||
|
||||
// Maximum allowable size
|
||||
#define NS_MAXSIZE nscoord_MAX
|
||||
|
||||
typedef mozilla::gfx::IntSize nsIntSize;
|
||||
|
||||
struct nsSize : public mozilla::gfx::BaseSize<nscoord, nsSize> {
|
||||
typedef mozilla::gfx::BaseSize<nscoord, nsSize> Super;
|
||||
|
||||
nsSize() : Super() {}
|
||||
nsSize(nscoord aWidth, nscoord aHeight) : Super(aWidth, aHeight) {}
|
||||
|
||||
inline mozilla::gfx::IntSize ScaleToNearestPixels(float aXScale, float aYScale,
|
||||
nscoord aAppUnitsPerPixel) const;
|
||||
inline mozilla::gfx::IntSize ToNearestPixels(nscoord aAppUnitsPerPixel) const;
|
||||
|
||||
/**
|
||||
* Return this size scaled to a different appunits per pixel (APP) ratio.
|
||||
* @param aFromAPP the APP to scale from
|
||||
* @param aToAPP the APP to scale to
|
||||
*/
|
||||
MOZ_MUST_USE inline nsSize
|
||||
ScaleToOtherAppUnits(int32_t aFromAPP, int32_t aToAPP) const;
|
||||
};
|
||||
|
||||
inline mozilla::gfx::IntSize
|
||||
nsSize::ScaleToNearestPixels(float aXScale, float aYScale,
|
||||
nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
return mozilla::gfx::IntSize(
|
||||
NSToIntRoundUp(NSAppUnitsToDoublePixels(width, aAppUnitsPerPixel) * aXScale),
|
||||
NSToIntRoundUp(NSAppUnitsToDoublePixels(height, aAppUnitsPerPixel) * aYScale));
|
||||
}
|
||||
|
||||
inline mozilla::gfx::IntSize
|
||||
nsSize::ToNearestPixels(nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
return ScaleToNearestPixels(1.0f, 1.0f, aAppUnitsPerPixel);
|
||||
}
|
||||
|
||||
inline nsSize
|
||||
nsSize::ScaleToOtherAppUnits(int32_t aFromAPP, int32_t aToAPP) const {
|
||||
if (aFromAPP != aToAPP) {
|
||||
nsSize size;
|
||||
size.width = NSToCoordRound(NSCoordScale(width, aFromAPP, aToAPP));
|
||||
size.height = NSToCoordRound(NSCoordScale(height, aFromAPP, aToAPP));
|
||||
return size;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline nsSize
|
||||
IntSizeToAppUnits(mozilla::gfx::IntSize aSize, nscoord aAppUnitsPerPixel)
|
||||
{
|
||||
return nsSize(NSIntPixelsToAppUnits(aSize.width, aAppUnitsPerPixel),
|
||||
NSIntPixelsToAppUnits(aSize.height, aAppUnitsPerPixel));
|
||||
}
|
||||
|
||||
#endif /* NSSIZE_H */
|
||||
129
gfx/src/nsThebesFontEnumerator.cpp
Normal file
129
gfx/src/nsThebesFontEnumerator.cpp
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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/. */
|
||||
|
||||
#include "nsThebesFontEnumerator.h"
|
||||
#include <stdint.h> // for uint32_t
|
||||
#include "gfxPlatform.h" // for gfxPlatform
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
|
||||
#include "nsCOMPtr.h" // for nsCOMPtr
|
||||
#include "nsDebug.h" // for NS_ENSURE_ARG_POINTER
|
||||
#include "nsError.h" // for NS_OK, NS_FAILED, nsresult
|
||||
#include "nsIAtom.h" // for nsIAtom, NS_Atomize
|
||||
#include "nsID.h"
|
||||
#include "nsMemory.h" // for nsMemory
|
||||
#include "nsString.h" // for nsAutoCString, nsAutoString, etc
|
||||
#include "nsTArray.h" // for nsTArray, nsTArray_Impl, etc
|
||||
#include "nscore.h" // for char16_t, NS_IMETHODIMP
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsThebesFontEnumerator, nsIFontEnumerator)
|
||||
|
||||
nsThebesFontEnumerator::nsThebesFontEnumerator()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThebesFontEnumerator::EnumerateAllFonts(uint32_t *aCount,
|
||||
char16_t ***aResult)
|
||||
{
|
||||
return EnumerateFonts (nullptr, nullptr, aCount, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThebesFontEnumerator::EnumerateFonts(const char *aLangGroup,
|
||||
const char *aGeneric,
|
||||
uint32_t *aCount,
|
||||
char16_t ***aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aCount);
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
|
||||
nsTArray<nsString> fontList;
|
||||
|
||||
nsAutoCString generic;
|
||||
if (aGeneric)
|
||||
generic.Assign(aGeneric);
|
||||
else
|
||||
generic.SetIsVoid(true);
|
||||
|
||||
nsCOMPtr<nsIAtom> langGroupAtom;
|
||||
if (aLangGroup) {
|
||||
nsAutoCString lowered;
|
||||
lowered.Assign(aLangGroup);
|
||||
ToLowerCase(lowered);
|
||||
langGroupAtom = NS_Atomize(lowered);
|
||||
}
|
||||
|
||||
nsresult rv = gfxPlatform::GetPlatform()->GetFontList(langGroupAtom, generic, fontList);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
*aCount = 0;
|
||||
*aResult = nullptr;
|
||||
/* XXX in this case, do we want to return the CSS generics? */
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
char16_t **fs = static_cast<char16_t **>
|
||||
(moz_xmalloc(fontList.Length() * sizeof(char16_t*)));
|
||||
for (uint32_t i = 0; i < fontList.Length(); i++) {
|
||||
fs[i] = ToNewUnicode(fontList[i]);
|
||||
}
|
||||
|
||||
*aResult = fs;
|
||||
*aCount = fontList.Length();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThebesFontEnumerator::HaveFontFor(const char *aLangGroup,
|
||||
bool *aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
|
||||
*aResult = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThebesFontEnumerator::GetDefaultFont(const char *aLangGroup,
|
||||
const char *aGeneric,
|
||||
char16_t **aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
*aResult = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThebesFontEnumerator::UpdateFontList(bool *_retval)
|
||||
{
|
||||
gfxPlatform::GetPlatform()->UpdateFontList();
|
||||
*_retval = false; // always return false for now
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThebesFontEnumerator::GetStandardFamilyName(const char16_t *aName,
|
||||
char16_t **aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
NS_ENSURE_ARG_POINTER(aName);
|
||||
|
||||
nsAutoString name(aName);
|
||||
if (name.IsEmpty()) {
|
||||
*aResult = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoString family;
|
||||
nsresult rv = gfxPlatform::GetPlatform()->
|
||||
GetStandardFamilyName(nsDependentString(aName), family);
|
||||
if (NS_FAILED(rv) || family.IsEmpty()) {
|
||||
*aResult = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
*aResult = ToNewUnicode(family);
|
||||
return NS_OK;
|
||||
}
|
||||
24
gfx/src/nsThebesFontEnumerator.h
Normal file
24
gfx/src/nsThebesFontEnumerator.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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 _NSTHEBESFONTENUMERATOR_H_
|
||||
#define _NSTHEBESFONTENUMERATOR_H_
|
||||
|
||||
#include "mozilla/Attributes.h" // for final
|
||||
#include "nsIFontEnumerator.h" // for NS_DECL_NSIFONTENUMERATOR, etc
|
||||
#include "nsISupports.h" // for NS_DECL_ISUPPORTS
|
||||
|
||||
class nsThebesFontEnumerator final : public nsIFontEnumerator
|
||||
{
|
||||
~nsThebesFontEnumerator() {}
|
||||
public:
|
||||
nsThebesFontEnumerator();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_DECL_NSIFONTENUMERATOR
|
||||
};
|
||||
|
||||
#endif /* _NSTHEBESFONTENUMERATOR_H_ */
|
||||
63
gfx/src/nsThebesGfxFactory.cpp
Normal file
63
gfx/src/nsThebesGfxFactory.cpp
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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/. */
|
||||
|
||||
#include "gfxPlatform.h" // for gfxPlatform
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
|
||||
#include "mozilla/Attributes.h" // for final
|
||||
#include "mozilla/Module.h" // for Module, Module::CIDEntry, etc
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "mozilla/mozalloc.h" // for operator new
|
||||
#include "nsCOMPtr.h" // for nsCOMPtr
|
||||
#include "nsError.h" // for NS_ERROR_NO_AGGREGATION, etc
|
||||
#include "nsGfxCIID.h" // for NS_FONT_ENUMERATOR_CID, etc
|
||||
#include "nsID.h" // for NS_DEFINE_NAMED_CID, etc
|
||||
#include "nsIScriptableRegion.h" // for nsIScriptableRegion
|
||||
#include "nsISupports.h" // for NS_DECL_ISUPPORTS, etc
|
||||
#include "nsScriptableRegion.h" // for nsScriptableRegion
|
||||
#include "nsThebesFontEnumerator.h" // for nsThebesFontEnumerator
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsThebesFontEnumerator)
|
||||
|
||||
static nsresult
|
||||
nsScriptableRegionConstructor(nsISupports *aOuter, REFNSIID aIID, void **aResult)
|
||||
{
|
||||
if (!aResult) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
*aResult = nullptr;
|
||||
if (aOuter) {
|
||||
return NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptableRegion> scriptableRgn = new nsScriptableRegion();
|
||||
return scriptableRgn->QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
NS_DEFINE_NAMED_CID(NS_FONT_ENUMERATOR_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_SCRIPTABLE_REGION_CID);
|
||||
|
||||
static const mozilla::Module::CIDEntry kThebesCIDs[] = {
|
||||
{ &kNS_FONT_ENUMERATOR_CID, false, nullptr, nsThebesFontEnumeratorConstructor },
|
||||
{ &kNS_SCRIPTABLE_REGION_CID, false, nullptr, nsScriptableRegionConstructor },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module::ContractIDEntry kThebesContracts[] = {
|
||||
{ "@mozilla.org/gfx/fontenumerator;1", &kNS_FONT_ENUMERATOR_CID },
|
||||
{ "@mozilla.org/gfx/region;1", &kNS_SCRIPTABLE_REGION_CID },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module kThebesModule = {
|
||||
mozilla::Module::kVersion,
|
||||
kThebesCIDs,
|
||||
kThebesContracts,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr
|
||||
};
|
||||
|
||||
NSMODULE_DEFN(nsGfxModule) = &kThebesModule;
|
||||
296
gfx/src/nsThemeConstants.h
Normal file
296
gfx/src/nsThemeConstants.h
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
/* 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/. */
|
||||
|
||||
// No appearance at all.
|
||||
#define NS_THEME_NONE 0
|
||||
|
||||
// A typical dialog button.
|
||||
#define NS_THEME_BUTTON 1
|
||||
|
||||
// A radio element within a radio group.
|
||||
#define NS_THEME_RADIO 2
|
||||
|
||||
// A checkbox element.
|
||||
#define NS_THEME_CHECKBOX 3
|
||||
|
||||
// A rectangular button that contains complex content
|
||||
// like images (e.g. HTML <button> elements)
|
||||
#define NS_THEME_BUTTON_BEVEL 7
|
||||
|
||||
// A themed focus outline (for outline:auto)
|
||||
#define NS_THEME_FOCUS_OUTLINE 8
|
||||
|
||||
// The toolbox that contains the toolbars.
|
||||
#define NS_THEME_TOOLBOX 11
|
||||
|
||||
// A toolbar in an application window.
|
||||
#define NS_THEME_TOOLBAR 12
|
||||
|
||||
// A single toolbar button (with no associated dropdown)
|
||||
#define NS_THEME_TOOLBARBUTTON 13
|
||||
|
||||
// A dual toolbar button (e.g., a Back button with a dropdown)
|
||||
#define NS_THEME_DUALBUTTON 14
|
||||
|
||||
// The dropdown portion of a toolbar button
|
||||
#define NS_THEME_TOOLBARBUTTON_DROPDOWN 15
|
||||
|
||||
// Various arrows that go in buttons
|
||||
#define NS_THEME_BUTTON_ARROW_UP 16
|
||||
#define NS_THEME_BUTTON_ARROW_DOWN 17
|
||||
#define NS_THEME_BUTTON_ARROW_NEXT 18
|
||||
#define NS_THEME_BUTTON_ARROW_PREVIOUS 19
|
||||
|
||||
// A separator. Can be horizontal or vertical.
|
||||
#define NS_THEME_SEPARATOR 20
|
||||
|
||||
// The gripper for a toolbar.
|
||||
#define NS_THEME_TOOLBARGRIPPER 21
|
||||
|
||||
// A splitter. Can be horizontal or vertical.
|
||||
#define NS_THEME_SPLITTER 22
|
||||
|
||||
// A status bar in a main application window.
|
||||
#define NS_THEME_STATUSBAR 23
|
||||
|
||||
// A single pane of a status bar.
|
||||
#define NS_THEME_STATUSBARPANEL 24
|
||||
|
||||
// The resizer background area in a status bar
|
||||
// for the resizer widget in the corner of a window.
|
||||
#define NS_THEME_RESIZERPANEL 25
|
||||
|
||||
// The resizer itself.
|
||||
#define NS_THEME_RESIZER 26
|
||||
|
||||
// List boxes
|
||||
#define NS_THEME_LISTBOX 31
|
||||
|
||||
// A listbox item
|
||||
#define NS_THEME_LISTITEM 32
|
||||
|
||||
// A tree widget
|
||||
#define NS_THEME_TREEVIEW 41
|
||||
|
||||
// A tree item
|
||||
#define NS_THEME_TREEITEM 42
|
||||
|
||||
// A tree widget twisty
|
||||
#define NS_THEME_TREETWISTY 43
|
||||
|
||||
// A tree widget branch line
|
||||
#define NS_THEME_TREELINE 44
|
||||
|
||||
// A listbox or tree widget header
|
||||
#define NS_THEME_TREEHEADER 45
|
||||
|
||||
// An individual header cell
|
||||
#define NS_THEME_TREEHEADERCELL 46
|
||||
|
||||
// The sort arrow for a header.
|
||||
#define NS_THEME_TREEHEADERSORTARROW 47
|
||||
|
||||
// Open tree widget twisty
|
||||
#define NS_THEME_TREETWISTYOPEN 48
|
||||
|
||||
// A horizontal progress bar.
|
||||
#define NS_THEME_PROGRESSBAR 51
|
||||
|
||||
// The progress bar's progress indicator
|
||||
#define NS_THEME_PROGRESSCHUNK 52
|
||||
|
||||
// A vertical progress bar.
|
||||
#define NS_THEME_PROGRESSBAR_VERTICAL 53
|
||||
|
||||
// A vertical progress chunk
|
||||
#define NS_THEME_PROGRESSCHUNK_VERTICAL 54
|
||||
|
||||
// A horizontal meter bar.
|
||||
#define NS_THEME_METERBAR 55
|
||||
|
||||
// The meter bar's meter indicator
|
||||
#define NS_THEME_METERCHUNK 56
|
||||
|
||||
// A single tab in a tab widget.
|
||||
#define NS_THEME_TAB 61
|
||||
|
||||
// A single pane (inside the tabpanels container)
|
||||
#define NS_THEME_TABPANEL 62
|
||||
|
||||
// The tab panels container.
|
||||
#define NS_THEME_TABPANELS 65
|
||||
|
||||
// The tabs scroll arrows (left/right)
|
||||
#define NS_THEME_TAB_SCROLL_ARROW_BACK 66
|
||||
#define NS_THEME_TAB_SCROLL_ARROW_FORWARD 67
|
||||
|
||||
// A tooltip
|
||||
#define NS_THEME_TOOLTIP 71
|
||||
|
||||
// A spin control (up/down control for time/date pickers)
|
||||
#define NS_THEME_SPINNER 72
|
||||
|
||||
// The up button of a spin control
|
||||
#define NS_THEME_SPINNER_UPBUTTON 73
|
||||
|
||||
// The down button of a spin control
|
||||
#define NS_THEME_SPINNER_DOWNBUTTON 74
|
||||
|
||||
// The textfield of a spin control
|
||||
#define NS_THEME_SPINNER_TEXTFIELD 75
|
||||
|
||||
// For HTML's <input type=number>
|
||||
#define NS_THEME_NUMBER_INPUT 76
|
||||
|
||||
// A scrollbar.
|
||||
#define NS_THEME_SCROLLBAR 80
|
||||
|
||||
// A small scrollbar.
|
||||
#define NS_THEME_SCROLLBAR_SMALL 81
|
||||
|
||||
// The scrollbar slider
|
||||
#define NS_THEME_SCROLLBAR_HORIZONTAL 82
|
||||
#define NS_THEME_SCROLLBAR_VERTICAL 83
|
||||
|
||||
// A scrollbar button (up/down/left/right)
|
||||
#define NS_THEME_SCROLLBARBUTTON_UP 84
|
||||
#define NS_THEME_SCROLLBARBUTTON_DOWN 85
|
||||
#define NS_THEME_SCROLLBARBUTTON_LEFT 86
|
||||
#define NS_THEME_SCROLLBARBUTTON_RIGHT 87
|
||||
|
||||
// The scrollbar track
|
||||
#define NS_THEME_SCROLLBARTRACK_HORIZONTAL 88
|
||||
#define NS_THEME_SCROLLBARTRACK_VERTICAL 89
|
||||
|
||||
// The scrollbar thumb
|
||||
#define NS_THEME_SCROLLBARTHUMB_HORIZONTAL 90
|
||||
#define NS_THEME_SCROLLBARTHUMB_VERTICAL 91
|
||||
|
||||
// A non-disappearing scrollbar.
|
||||
#define NS_THEME_SCROLLBAR_NON_DISAPPEARING 92
|
||||
|
||||
// A textfield or text area
|
||||
#define NS_THEME_TEXTFIELD 95
|
||||
|
||||
// The caret of a text area
|
||||
#define NS_THEME_CARET 96
|
||||
|
||||
// A multiline text field
|
||||
#define NS_THEME_TEXTFIELD_MULTILINE 97
|
||||
|
||||
// A searchfield
|
||||
#define NS_THEME_SEARCHFIELD 98
|
||||
|
||||
// A dropdown list.
|
||||
#define NS_THEME_MENULIST 101
|
||||
|
||||
// The dropdown button(s) that open up a dropdown list.
|
||||
#define NS_THEME_MENULIST_BUTTON 102
|
||||
|
||||
// The text part of a dropdown list, to left of button
|
||||
#define NS_THEME_MENULIST_TEXT 103
|
||||
|
||||
// An editable textfield with a dropdown list (a combobox)
|
||||
#define NS_THEME_MENULIST_TEXTFIELD 104
|
||||
|
||||
// A slider
|
||||
#define NS_THEME_SCALE_HORIZONTAL 111
|
||||
#define NS_THEME_SCALE_VERTICAL 112
|
||||
|
||||
// A slider's thumb
|
||||
#define NS_THEME_SCALETHUMB_HORIZONTAL 113
|
||||
#define NS_THEME_SCALETHUMB_VERTICAL 114
|
||||
|
||||
// If the platform supports it, the left/right chunks
|
||||
// of the slider thumb
|
||||
#define NS_THEME_SCALETHUMBSTART 115
|
||||
#define NS_THEME_SCALETHUMBEND 116
|
||||
|
||||
// The ticks for a slider.
|
||||
#define NS_THEME_SCALETHUMBTICK 117
|
||||
|
||||
// nsRangeFrame and its subparts
|
||||
#define NS_THEME_RANGE 120
|
||||
#define NS_THEME_RANGE_THUMB 121
|
||||
|
||||
// A groupbox
|
||||
#define NS_THEME_GROUPBOX 149
|
||||
|
||||
// A generic container that always repaints on state
|
||||
// changes. This is a hack to make checkboxes and
|
||||
// radio buttons work.
|
||||
#define NS_THEME_CHECKBOX_CONTAINER 150
|
||||
#define NS_THEME_RADIO_CONTAINER 151
|
||||
|
||||
// The label part of a checkbox or radio button, used for painting
|
||||
// a focus outline.
|
||||
#define NS_THEME_CHECKBOX_LABEL 152
|
||||
#define NS_THEME_RADIO_LABEL 153
|
||||
|
||||
// The focus outline box inside of a button
|
||||
#define NS_THEME_BUTTON_FOCUS 154
|
||||
|
||||
// Window and dialog backgrounds
|
||||
#define NS_THEME_WINDOW 200
|
||||
#define NS_THEME_DIALOG 201
|
||||
|
||||
// Menu Bar background
|
||||
#define NS_THEME_MENUBAR 210
|
||||
// Menu Popup background
|
||||
#define NS_THEME_MENUPOPUP 211
|
||||
// <menu> and <menuitem> appearances
|
||||
#define NS_THEME_MENUITEM 212
|
||||
#define NS_THEME_CHECKMENUITEM 213
|
||||
#define NS_THEME_RADIOMENUITEM 214
|
||||
|
||||
// menu checkbox/radio appearances
|
||||
#define NS_THEME_MENUCHECKBOX 215
|
||||
#define NS_THEME_MENURADIO 216
|
||||
#define NS_THEME_MENUSEPARATOR 217
|
||||
#define NS_THEME_MENUARROW 218
|
||||
// An image in the menu gutter, like in bookmarks or history
|
||||
#define NS_THEME_MENUIMAGE 219
|
||||
// For text on non-iconic menuitems only
|
||||
#define NS_THEME_MENUITEMTEXT 220
|
||||
|
||||
// Vista Rebars
|
||||
#define NS_THEME_WIN_COMMUNICATIONS_TOOLBOX 221
|
||||
#define NS_THEME_WIN_MEDIA_TOOLBOX 222
|
||||
#define NS_THEME_WIN_BROWSERTABBAR_TOOLBOX 223
|
||||
|
||||
// Titlebar elements on the Mac
|
||||
#define NS_THEME_MAC_FULLSCREEN_BUTTON 226
|
||||
|
||||
// Mac help button
|
||||
#define NS_THEME_MAC_HELP_BUTTON 227
|
||||
|
||||
// Vista glass
|
||||
#define NS_THEME_WIN_BORDERLESS_GLASS 229
|
||||
#define NS_THEME_WIN_GLASS 230
|
||||
|
||||
// Windows themed window frame elements
|
||||
#define NS_THEME_WINDOW_TITLEBAR 231
|
||||
#define NS_THEME_WINDOW_TITLEBAR_MAXIMIZED 232
|
||||
#define NS_THEME_WINDOW_FRAME_LEFT 233
|
||||
#define NS_THEME_WINDOW_FRAME_RIGHT 234
|
||||
#define NS_THEME_WINDOW_FRAME_BOTTOM 235
|
||||
#define NS_THEME_WINDOW_BUTTON_CLOSE 236
|
||||
#define NS_THEME_WINDOW_BUTTON_MINIMIZE 237
|
||||
#define NS_THEME_WINDOW_BUTTON_MAXIMIZE 238
|
||||
#define NS_THEME_WINDOW_BUTTON_RESTORE 239
|
||||
#define NS_THEME_WINDOW_BUTTON_BOX 240
|
||||
#define NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED 241
|
||||
|
||||
// moz-apperance style used in setting proper glass margins
|
||||
#define NS_THEME_WIN_EXCLUDE_GLASS 242
|
||||
|
||||
#define NS_THEME_MAC_VIBRANCY_LIGHT 243
|
||||
#define NS_THEME_MAC_VIBRANCY_DARK 244
|
||||
#define NS_THEME_MAC_DISCLOSURE_BUTTON_OPEN 245
|
||||
#define NS_THEME_MAC_DISCLOSURE_BUTTON_CLOSED 246
|
||||
|
||||
#define NS_THEME_GTK_INFO_BAR 247
|
||||
#define NS_THEME_MAC_SOURCE_LIST 248
|
||||
#define NS_THEME_MAC_SOURCE_LIST_SELECTION 249
|
||||
#define NS_THEME_MAC_ACTIVE_SOURCE_LIST_SELECTION 250
|
||||
23
gfx/src/nsTransform2D.cpp
Normal file
23
gfx/src/nsTransform2D.cpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/* -*- 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 "nsTransform2D.h"
|
||||
|
||||
void nsTransform2D :: TransformCoord(nscoord *ptX, nscoord *ptY) const
|
||||
{
|
||||
*ptX = NSToCoordRound(*ptX * m00 + m20);
|
||||
*ptY = NSToCoordRound(*ptY * m11 + m21);
|
||||
}
|
||||
|
||||
void nsTransform2D :: TransformCoord(nscoord *aX, nscoord *aY, nscoord *aWidth, nscoord *aHeight) const
|
||||
{
|
||||
nscoord x2 = *aX + *aWidth;
|
||||
nscoord y2 = *aY + *aHeight;
|
||||
TransformCoord(aX, aY);
|
||||
TransformCoord(&x2, &y2);
|
||||
*aWidth = x2 - *aX;
|
||||
*aHeight = y2 - *aY;
|
||||
}
|
||||
86
gfx/src/nsTransform2D.h
Normal file
86
gfx/src/nsTransform2D.h
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/* -*- 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 nsTransform2D_h___
|
||||
#define nsTransform2D_h___
|
||||
|
||||
#include "nsCoord.h"
|
||||
|
||||
class nsTransform2D
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* This represents the following matrix (note that the order of row/column
|
||||
* indices is opposite to usual notation)
|
||||
*
|
||||
* / m00 0 m20 \
|
||||
* M = | 0 m11 m21 |
|
||||
* \ 0 0 1 /
|
||||
*
|
||||
* Transformation of a coordinate (x, y) is obtained by setting
|
||||
* v = (x, y, 1)^T and evaluating M . v
|
||||
**/
|
||||
|
||||
float m00, m11, m20, m21;
|
||||
|
||||
public:
|
||||
nsTransform2D(void) { m20 = m21 = 0.0f; m00 = m11 = 1.0f; }
|
||||
|
||||
~nsTransform2D(void) { }
|
||||
|
||||
/**
|
||||
* set this transform to a translation
|
||||
*
|
||||
* @param tx, x translation
|
||||
* @param ty, y translation
|
||||
**/
|
||||
|
||||
void SetToTranslate(float tx, float ty) { m00 = m11 = 1.0f; m20 = tx; m21 = ty; }
|
||||
|
||||
/**
|
||||
* get the translation portion of this transform
|
||||
*
|
||||
* @param pt, Point to return translation values in
|
||||
**/
|
||||
|
||||
void GetTranslationCoord(nscoord *ptX, nscoord *ptY) const { *ptX = NSToCoordRound(m20); *ptY = NSToCoordRound(m21); }
|
||||
|
||||
/**
|
||||
* apply matrix to vector
|
||||
*
|
||||
* @param pt Point to transform
|
||||
**/
|
||||
|
||||
void TransformCoord(nscoord *ptX, nscoord *ptY) const;
|
||||
|
||||
/**
|
||||
* apply matrix to rect
|
||||
*
|
||||
* @param rect Rect to transform
|
||||
**/
|
||||
|
||||
void TransformCoord(nscoord *aX, nscoord *aY, nscoord *aWidth, nscoord *aHeight) const;
|
||||
|
||||
/**
|
||||
* add a scale to a Transform via x, y pair
|
||||
*
|
||||
* @param ptX x value to add as x scale
|
||||
* @param ptY y value to add as y scale
|
||||
**/
|
||||
|
||||
void AddScale(float ptX, float ptY) { m00 *= ptX; m11 *= ptY; }
|
||||
|
||||
/**
|
||||
* Set the scale (overriding any previous calls to AddScale, but leaving
|
||||
* any existing translation).
|
||||
*
|
||||
* @param ptX x value to add as x scale
|
||||
* @param ptY y value to add as y scale
|
||||
**/
|
||||
|
||||
void SetScale(float ptX, float ptY) { m00 = ptX; m11 = ptY; }
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue