зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound
This commit is contained in:
Коммит
48d1be80d3
|
@ -332,12 +332,8 @@ EffectCompositor::PostRestyleForAnimation(dom::Element* aElement,
|
|||
// second traversal so we don't need to post any restyle requests to the
|
||||
// PresShell.
|
||||
return;
|
||||
} else if (!mPresContext->RestyleManager()->IsInStyleRefresh()) {
|
||||
// FIXME: stylo only supports Self and Subtree hints now, so we override
|
||||
// it for stylo if we are not in process of restyling.
|
||||
hint = eRestyle_Self | eRestyle_Subtree;
|
||||
} else {
|
||||
MOZ_ASSERT_UNREACHABLE("Should not request restyle");
|
||||
MOZ_ASSERT(!mPresContext->RestyleManager()->IsInStyleRefresh());
|
||||
}
|
||||
}
|
||||
mPresContext->PresShell()->RestyleForAnimation(element, hint);
|
||||
|
@ -983,8 +979,8 @@ EffectCompositor::PreTraverse()
|
|||
// We can't call PostRestyleEvent directly here since we are still in the
|
||||
// middle of the servo traversal.
|
||||
mPresContext->RestyleManager()->AsServo()->
|
||||
PostRestyleEventForAnimations(target.mElement,
|
||||
eRestyle_Self | eRestyle_Subtree);
|
||||
PostRestyleEventForAnimations(target.mElement, eRestyle_CSSAnimations);
|
||||
|
||||
foundElementsNeedingRestyle = true;
|
||||
|
||||
EffectSet* effects =
|
||||
|
@ -1035,7 +1031,7 @@ EffectCompositor::PreTraverse(dom::Element* aElement, nsIAtom* aPseudoTagOrNull)
|
|||
}
|
||||
|
||||
mPresContext->RestyleManager()->AsServo()->
|
||||
PostRestyleEventForAnimations(aElement, eRestyle_Self);
|
||||
PostRestyleEventForAnimations(aElement, eRestyle_CSSAnimations);
|
||||
|
||||
EffectSet* effects = EffectSet::GetEffectSet(aElement, pseudoType);
|
||||
if (effects) {
|
||||
|
|
|
@ -407,33 +407,6 @@ KeyframeEffectReadOnly::CompositeValue(
|
|||
return StyleAnimationValue();
|
||||
}
|
||||
|
||||
StyleAnimationValue
|
||||
KeyframeEffectReadOnly::ResolveBaseStyle(nsCSSPropertyID aProperty,
|
||||
nsStyleContext* aStyleContext)
|
||||
{
|
||||
StyleAnimationValue result;
|
||||
if (mBaseStyleValues.Get(aProperty, &result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
RefPtr<nsStyleContext> styleContextWithoutAnimation =
|
||||
aStyleContext->PresContext()->StyleSet()->AsGecko()->
|
||||
ResolveStyleByRemovingAnimation(mTarget->mElement,
|
||||
aStyleContext,
|
||||
eRestyle_AllHintsWithAnimations);
|
||||
DebugOnly<bool> success =
|
||||
StyleAnimationValue::ExtractComputedValue(aProperty,
|
||||
styleContextWithoutAnimation,
|
||||
result);
|
||||
|
||||
MOZ_ASSERT(success, "Should be able to extract computed animation value");
|
||||
MOZ_ASSERT(!result.IsNull(), "Should have a valid StyleAnimationValue");
|
||||
|
||||
mBaseStyleValues.Put(aProperty, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
StyleAnimationValue
|
||||
KeyframeEffectReadOnly::GetUnderlyingStyle(
|
||||
nsCSSPropertyID aProperty,
|
||||
|
@ -490,18 +463,52 @@ KeyframeEffectReadOnly::EnsureBaseStyles(
|
|||
|
||||
mBaseStyleValues.Clear();
|
||||
|
||||
RefPtr<nsStyleContext> cachedBaseStyleContext;
|
||||
|
||||
for (const AnimationProperty& property : aProperties) {
|
||||
for (const AnimationPropertySegment& segment : property.mSegments) {
|
||||
if (segment.HasReplacableValues()) {
|
||||
if (segment.HasReplaceableValues()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Unused << ResolveBaseStyle(property.mProperty, aStyleContext);
|
||||
EnsureBaseStyle(property.mProperty,
|
||||
aStyleContext,
|
||||
cachedBaseStyleContext);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
KeyframeEffectReadOnly::EnsureBaseStyle(
|
||||
nsCSSPropertyID aProperty,
|
||||
nsStyleContext* aStyleContext,
|
||||
RefPtr<nsStyleContext>& aCachedBaseStyleContext)
|
||||
{
|
||||
if (mBaseStyleValues.Contains(aProperty)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aCachedBaseStyleContext) {
|
||||
aCachedBaseStyleContext =
|
||||
aStyleContext->PresContext()->StyleSet()->AsGecko()->
|
||||
ResolveStyleByRemovingAnimation(mTarget->mElement,
|
||||
aStyleContext,
|
||||
eRestyle_AllHintsWithAnimations);
|
||||
}
|
||||
|
||||
StyleAnimationValue result;
|
||||
DebugOnly<bool> success =
|
||||
StyleAnimationValue::ExtractComputedValue(aProperty,
|
||||
aCachedBaseStyleContext,
|
||||
result);
|
||||
|
||||
MOZ_ASSERT(success, "Should be able to extract computed animation value");
|
||||
MOZ_ASSERT(!result.IsNull(), "Should have a valid StyleAnimationValue");
|
||||
|
||||
mBaseStyleValues.Put(aProperty, result);
|
||||
}
|
||||
|
||||
void
|
||||
KeyframeEffectReadOnly::WillComposeStyle()
|
||||
{
|
||||
|
@ -1653,7 +1660,7 @@ KeyframeEffectReadOnly::CalculateCumulativeChangeHint(
|
|||
// we can't throttle animations which will not cause any layout changes
|
||||
// on invisible elements because we can't calculate the change hint for
|
||||
// such properties until we compose it.
|
||||
if (!segment.HasReplacableValues()) {
|
||||
if (!segment.HasReplaceableValues()) {
|
||||
mCumulativeChangeHint = ~nsChangeHint_Hints_CanIgnoreIfNotVisible;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -65,18 +65,18 @@ struct AnimationPropertySegment
|
|||
dom::CompositeOperation mFromComposite = dom::CompositeOperation::Replace;
|
||||
dom::CompositeOperation mToComposite = dom::CompositeOperation::Replace;
|
||||
|
||||
bool HasReplacableValues() const
|
||||
bool HasReplaceableValues() const
|
||||
{
|
||||
return HasReplacableFromValue() && HasReplacableToValue();
|
||||
return HasReplaceableFromValue() && HasReplaceableToValue();
|
||||
}
|
||||
|
||||
bool HasReplacableFromValue() const
|
||||
bool HasReplaceableFromValue() const
|
||||
{
|
||||
return !mFromValue.IsNull() &&
|
||||
mFromComposite == dom::CompositeOperation::Replace;
|
||||
}
|
||||
|
||||
bool HasReplacableToValue() const
|
||||
bool HasReplaceableToValue() const
|
||||
{
|
||||
return !mToValue.IsNull() &&
|
||||
mToComposite == dom::CompositeOperation::Replace;
|
||||
|
@ -417,9 +417,14 @@ protected:
|
|||
// FIXME: Bug 1311257: Support missing keyframes.
|
||||
}
|
||||
|
||||
// Returns the base style resolved by |aStyleContext| for |aProperty|.
|
||||
StyleAnimationValue ResolveBaseStyle(nsCSSPropertyID aProperty,
|
||||
nsStyleContext* aStyleContext);
|
||||
// If no base style is already stored for |aProperty|, resolves the base style
|
||||
// for |aProperty| using |aStyleContext| and stores it in mBaseStyleValues.
|
||||
// If |aCachedBaseStyleContext| is non-null, it will be used, otherwise the
|
||||
// base style context will be resolved and stored in
|
||||
// |aCachedBaseStyleContext|.
|
||||
void EnsureBaseStyle(nsCSSPropertyID aProperty,
|
||||
nsStyleContext* aStyleContext,
|
||||
RefPtr<nsStyleContext>& aCachedBaseStyleContext);
|
||||
|
||||
Maybe<OwningAnimationTarget> mTarget;
|
||||
|
||||
|
|
|
@ -214,6 +214,11 @@ enum {
|
|||
// Whether this node has dirty descendants for Servo's style system.
|
||||
NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO = NODE_SHARED_RESTYLE_BIT_1,
|
||||
|
||||
// Whether this node has dirty descendants for animation-only restyle for
|
||||
// Servo's style system.
|
||||
NODE_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO =
|
||||
NODE_SHARED_RESTYLE_BIT_2,
|
||||
|
||||
// Remaining bits are node type specific.
|
||||
NODE_TYPE_SPECIFIC_BITS_OFFSET = 23
|
||||
};
|
||||
|
|
|
@ -885,9 +885,6 @@ private:
|
|||
MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
|
||||
("HTMLMediaElement::AudioChannelAgentCallback, SetAudioChannelSuspended, "
|
||||
"this = %p, aSuspend = %s\n", this, SuspendTypeToStr(aSuspend)));
|
||||
|
||||
NotifyAudioPlaybackChanged(
|
||||
AudioChannelService::AudibleChangedReasons::ePauseStateChanged);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -908,6 +905,9 @@ private:
|
|||
if (rv.Failed()) {
|
||||
NS_WARNING("Not able to resume from AudioChannel.");
|
||||
}
|
||||
|
||||
NotifyAudioPlaybackChanged(
|
||||
AudioChannelService::AudibleChangedReasons::ePauseStateChanged);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -925,6 +925,8 @@ private:
|
|||
return;
|
||||
}
|
||||
}
|
||||
NotifyAudioPlaybackChanged(
|
||||
AudioChannelService::AudibleChangedReasons::ePauseStateChanged);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1015,8 +1017,9 @@ private:
|
|||
return AudioChannelService::AudibleState::eMaybeAudible;
|
||||
}
|
||||
|
||||
// Media is suspended.
|
||||
if (mSuspended != nsISuspendedTypes::NONE_SUSPENDED) {
|
||||
// Suspended or paused media doesn't produce any sound.
|
||||
if (mSuspended != nsISuspendedTypes::NONE_SUSPENDED ||
|
||||
mOwner->mPaused) {
|
||||
return AudioChannelService::AudibleState::eNotAudible;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#include "mozilla/net/CaptivePortalService.h"
|
||||
#include "mozilla/plugins/PluginInstanceParent.h"
|
||||
#include "mozilla/plugins/PluginModuleParent.h"
|
||||
#include "mozilla/widget/ScreenManager.h"
|
||||
#include "mozilla/widget/WidgetMessageUtils.h"
|
||||
#include "nsBaseDragService.h"
|
||||
#include "mozilla/media/MediaChild.h"
|
||||
|
@ -99,7 +100,6 @@
|
|||
#include "nsIMutable.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsScreenManagerProxy.h"
|
||||
#include "nsMemoryInfoDumper.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsStyleSheetService.h"
|
||||
|
@ -1748,28 +1748,6 @@ ContentChild::DeallocPParentToChildStreamChild(PParentToChildStreamChild* aActor
|
|||
return nsIContentChild::DeallocPParentToChildStreamChild(aActor);
|
||||
}
|
||||
|
||||
PScreenManagerChild*
|
||||
ContentChild::AllocPScreenManagerChild(uint32_t* aNumberOfScreens,
|
||||
float* aSystemDefaultScale,
|
||||
bool* aSuccess)
|
||||
{
|
||||
// The ContentParent should never attempt to allocate the
|
||||
// nsScreenManagerProxy. Instead, the nsScreenManagerProxy
|
||||
// service is requested and instantiated via XPCOM, and the
|
||||
// constructor of nsScreenManagerProxy sets up the IPC connection.
|
||||
MOZ_CRASH("Should never get here!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::DeallocPScreenManagerChild(PScreenManagerChild* aService)
|
||||
{
|
||||
// nsScreenManagerProxy is AddRef'd in its constructor.
|
||||
nsScreenManagerProxy *child = static_cast<nsScreenManagerProxy*>(aService);
|
||||
child->Release();
|
||||
return true;
|
||||
}
|
||||
|
||||
PPSMContentDownloaderChild*
|
||||
ContentChild::AllocPPSMContentDownloaderChild(const uint32_t& aCertType)
|
||||
{
|
||||
|
@ -3268,7 +3246,14 @@ ContentChild::RecvSetPermissionsWithKey(const nsCString& aPermissionKey,
|
|||
nsCOMPtr<nsIPermissionManager> permissionManager =
|
||||
services::GetPermissionManager();
|
||||
permissionManager->SetPermissionsWithKey(aPermissionKey, aPerms);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentChild::RecvRefreshScreens(nsTArray<ScreenDetails>&& aScreens)
|
||||
{
|
||||
ScreenManager& screenManager = ScreenManager::GetSingleton();
|
||||
screenManager.Refresh(Move(aScreens));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
|
|
@ -242,13 +242,6 @@ public:
|
|||
virtual PParentToChildStreamChild* AllocPParentToChildStreamChild() override;
|
||||
virtual bool DeallocPParentToChildStreamChild(PParentToChildStreamChild*) override;
|
||||
|
||||
virtual PScreenManagerChild*
|
||||
AllocPScreenManagerChild(uint32_t* aNumberOfScreens,
|
||||
float* aSystemDefaultScale,
|
||||
bool* aSuccess) override;
|
||||
|
||||
virtual bool DeallocPScreenManagerChild(PScreenManagerChild*) override;
|
||||
|
||||
virtual PPSMContentDownloaderChild*
|
||||
AllocPPSMContentDownloaderChild( const uint32_t& aCertType) override;
|
||||
|
||||
|
@ -477,6 +470,9 @@ public:
|
|||
|
||||
virtual mozilla::ipc::IPCResult RecvParentActivated(PBrowserChild* aTab, const bool& aActivated) override;
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvRefreshScreens(nsTArray<ScreenDetails>&& aScreens) override;
|
||||
|
||||
// Get the directory for IndexedDB files. We query the parent for this and
|
||||
// cache the value
|
||||
nsString &GetIndexedDBPath();
|
||||
|
|
|
@ -97,6 +97,7 @@
|
|||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/TelemetryIPC.h"
|
||||
#include "mozilla/WebBrowserPersistDocumentParent.h"
|
||||
#include "mozilla/widget/ScreenManager.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsAnonymousTemporaryFile.h"
|
||||
#include "nsAppRunner.h"
|
||||
|
@ -162,7 +163,6 @@
|
|||
#include "PreallocatedProcessManager.h"
|
||||
#include "ProcessPriorityManager.h"
|
||||
#include "SandboxHal.h"
|
||||
#include "ScreenManagerParent.h"
|
||||
#include "SourceSurfaceRawData.h"
|
||||
#include "TabParent.h"
|
||||
#include "URIUtils.h"
|
||||
|
@ -2233,6 +2233,9 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority,
|
|||
storage->GetAll(&entry.items());
|
||||
xpcomInit.dataStorage().AppendElement(Move(entry));
|
||||
}
|
||||
// Must send screen info before send initialData
|
||||
ScreenManager& screenManager = ScreenManager::GetSingleton();
|
||||
screenManager.CopyScreensToRemote(this);
|
||||
|
||||
Unused << SendSetXPCOMProcessAttributes(xpcomInit, initialData, lnfCache);
|
||||
|
||||
|
@ -3136,21 +3139,6 @@ ContentParent::DeallocPParentToChildStreamParent(PParentToChildStreamParent* aAc
|
|||
return nsIContentParent::DeallocPParentToChildStreamParent(aActor);
|
||||
}
|
||||
|
||||
PScreenManagerParent*
|
||||
ContentParent::AllocPScreenManagerParent(uint32_t* aNumberOfScreens,
|
||||
float* aSystemDefaultScale,
|
||||
bool* aSuccess)
|
||||
{
|
||||
return new ScreenManagerParent(aNumberOfScreens, aSystemDefaultScale, aSuccess);
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::DeallocPScreenManagerParent(PScreenManagerParent* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
PPSMContentDownloaderParent*
|
||||
ContentParent::AllocPPSMContentDownloaderParent(const uint32_t& aCertType)
|
||||
{
|
||||
|
|
|
@ -446,14 +446,6 @@ public:
|
|||
virtual bool
|
||||
DeallocPParentToChildStreamParent(PParentToChildStreamParent* aActor) override;
|
||||
|
||||
virtual PScreenManagerParent*
|
||||
AllocPScreenManagerParent(uint32_t* aNumberOfScreens,
|
||||
float* aSystemDefaultScale,
|
||||
bool* aSuccess) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPScreenManagerParent(PScreenManagerParent* aActor) override;
|
||||
|
||||
virtual PHalParent* AllocPHalParent() override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvPHalConstructor(PHalParent* aActor) override
|
||||
|
|
|
@ -16,6 +16,11 @@ using struct mozilla::void_t
|
|||
using struct mozilla::SerializedStructuredCloneBuffer
|
||||
from "ipc/IPCMessageUtils.h";
|
||||
|
||||
using LayoutDeviceIntRect from "Units.h";
|
||||
using DesktopIntRect from "Units.h";
|
||||
using DesktopToLayoutDeviceScale from "Units.h";
|
||||
using CSSToLayoutDeviceScale from "Units.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -178,5 +183,16 @@ struct IPCDataTransfer
|
|||
IPCDataTransferItem[] items;
|
||||
};
|
||||
|
||||
struct ScreenDetails {
|
||||
LayoutDeviceIntRect rect;
|
||||
DesktopIntRect rectDisplayPix;
|
||||
LayoutDeviceIntRect availRect;
|
||||
DesktopIntRect availRectDisplayPix;
|
||||
int32_t pixelDepth;
|
||||
int32_t colorDepth;
|
||||
DesktopToLayoutDeviceScale contentsScaleFactor;
|
||||
CSSToLayoutDeviceScale defaultCSSScaleFactor;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -28,7 +28,6 @@ using class mozilla::gfx::Matrix from "mozilla/gfx/Matrix.h";
|
|||
using struct gfxSize from "gfxPoint.h";
|
||||
using CSSRect from "Units.h";
|
||||
using CSSSize from "Units.h";
|
||||
using mozilla::LayoutDeviceIntRect from "Units.h";
|
||||
using mozilla::LayoutDeviceIntPoint from "Units.h";
|
||||
using mozilla::LayoutDevicePoint from "Units.h";
|
||||
using mozilla::ScreenIntPoint from "Units.h";
|
||||
|
|
|
@ -30,7 +30,6 @@ include protocol PChildToParentStream;
|
|||
include protocol PParentToChildStream;
|
||||
include protocol POfflineCacheUpdate;
|
||||
include protocol PRenderFrame;
|
||||
include protocol PScreenManager;
|
||||
include protocol PSpeechSynthesis;
|
||||
include protocol PStorage;
|
||||
include protocol PTestShell;
|
||||
|
@ -289,7 +288,6 @@ nested(upto inside_cpow) sync protocol PContent
|
|||
manages PPrinting;
|
||||
manages PChildToParentStream;
|
||||
manages PParentToChildStream;
|
||||
manages PScreenManager;
|
||||
manages PSpeechSynthesis;
|
||||
manages PStorage;
|
||||
manages PTestShell;
|
||||
|
@ -595,6 +593,8 @@ child:
|
|||
|
||||
async SetPermissionsWithKey(nsCString aPermissionKey, Permission[] aPermissions);
|
||||
|
||||
async RefreshScreens(ScreenDetails[] aScreens);
|
||||
|
||||
parent:
|
||||
async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
|
||||
|
||||
|
@ -711,11 +711,6 @@ parent:
|
|||
|
||||
async PChildToParentStream();
|
||||
|
||||
nested(inside_sync) sync PScreenManager()
|
||||
returns (uint32_t numberOfScreens,
|
||||
float systemDefaultScale,
|
||||
bool success);
|
||||
|
||||
async PSpeechSynthesis();
|
||||
|
||||
nested(inside_cpow) async PStorage();
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PBrowser;
|
||||
include protocol PContent;
|
||||
|
||||
include "mozilla/GfxMessageUtils.h";
|
||||
|
||||
using nsIntRect from "nsRect.h";
|
||||
using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct ScreenDetails {
|
||||
uint32_t id;
|
||||
nsIntRect rect;
|
||||
nsIntRect rectDisplayPix;
|
||||
nsIntRect availRect;
|
||||
nsIntRect availRectDisplayPix;
|
||||
int32_t pixelDepth;
|
||||
int32_t colorDepth;
|
||||
double contentsScaleFactor;
|
||||
double defaultCSSScaleFactor;
|
||||
};
|
||||
|
||||
nested(upto inside_cpow) sync protocol PScreenManager
|
||||
{
|
||||
manager PContent;
|
||||
|
||||
parent:
|
||||
nested(inside_sync) sync Refresh()
|
||||
returns (uint32_t numberOfScreens,
|
||||
float systemDefaultScale,
|
||||
bool success);
|
||||
|
||||
nested(inside_cpow) sync ScreenRefresh(uint32_t aId)
|
||||
returns (ScreenDetails screen,
|
||||
bool success);
|
||||
|
||||
nested(inside_sync) sync GetPrimaryScreen()
|
||||
returns (ScreenDetails screen,
|
||||
bool success);
|
||||
|
||||
nested(inside_sync) sync ScreenForRect(int32_t aLeft,
|
||||
int32_t aTop,
|
||||
int32_t aWidth,
|
||||
int32_t aHeight)
|
||||
returns (ScreenDetails screen,
|
||||
bool success);
|
||||
|
||||
nested(inside_cpow) sync ScreenForBrowser(TabId aTabId)
|
||||
returns (ScreenDetails screen,
|
||||
bool success);
|
||||
|
||||
child:
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -1,234 +0,0 @@
|
|||
/* -*- 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 "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "ScreenManagerParent.h"
|
||||
#include "ContentProcessManager.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
static const char *sScreenManagerContractID = "@mozilla.org/gfx/screenmanager;1";
|
||||
|
||||
ScreenManagerParent::ScreenManagerParent(uint32_t* aNumberOfScreens,
|
||||
float* aSystemDefaultScale,
|
||||
bool* aSuccess)
|
||||
{
|
||||
mScreenMgr = do_GetService(sScreenManagerContractID);
|
||||
if (!mScreenMgr) {
|
||||
MOZ_CRASH("Couldn't get nsIScreenManager from ScreenManagerParent.");
|
||||
}
|
||||
|
||||
Unused << RecvRefresh(aNumberOfScreens, aSystemDefaultScale, aSuccess);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ScreenManagerParent::RecvRefresh(uint32_t* aNumberOfScreens,
|
||||
float* aSystemDefaultScale,
|
||||
bool* aSuccess)
|
||||
{
|
||||
*aSuccess = false;
|
||||
|
||||
nsresult rv = mScreenMgr->GetNumberOfScreens(aNumberOfScreens);
|
||||
if (NS_FAILED(rv)) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
rv = mScreenMgr->GetSystemDefaultScale(aSystemDefaultScale);
|
||||
if (NS_FAILED(rv)) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
*aSuccess = true;
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ScreenManagerParent::RecvScreenRefresh(const uint32_t& aId,
|
||||
ScreenDetails* aRetVal,
|
||||
bool* aSuccess)
|
||||
{
|
||||
*aSuccess = false;
|
||||
|
||||
nsCOMPtr<nsIScreen> screen;
|
||||
nsresult rv = mScreenMgr->ScreenForId(aId, getter_AddRefs(screen));
|
||||
if (NS_FAILED(rv)) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
ScreenDetails details;
|
||||
Unused << ExtractScreenDetails(screen, details);
|
||||
|
||||
*aRetVal = details;
|
||||
*aSuccess = true;
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ScreenManagerParent::RecvGetPrimaryScreen(ScreenDetails* aRetVal,
|
||||
bool* aSuccess)
|
||||
{
|
||||
*aSuccess = false;
|
||||
|
||||
nsCOMPtr<nsIScreen> screen;
|
||||
nsresult rv = mScreenMgr->GetPrimaryScreen(getter_AddRefs(screen));
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, IPC_OK());
|
||||
|
||||
ScreenDetails details;
|
||||
if (!ExtractScreenDetails(screen, details)) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
*aRetVal = details;
|
||||
*aSuccess = true;
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ScreenManagerParent::RecvScreenForRect(const int32_t& aLeft,
|
||||
const int32_t& aTop,
|
||||
const int32_t& aWidth,
|
||||
const int32_t& aHeight,
|
||||
ScreenDetails* aRetVal,
|
||||
bool* aSuccess)
|
||||
{
|
||||
*aSuccess = false;
|
||||
|
||||
nsCOMPtr<nsIScreen> screen;
|
||||
nsresult rv = mScreenMgr->ScreenForRect(aLeft, aTop, aWidth, aHeight, getter_AddRefs(screen));
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, IPC_OK());
|
||||
|
||||
ScreenDetails details;
|
||||
if (!ExtractScreenDetails(screen, details)) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
*aRetVal = details;
|
||||
*aSuccess = true;
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ScreenManagerParent::RecvScreenForBrowser(const TabId& aTabId,
|
||||
ScreenDetails* aRetVal,
|
||||
bool* aSuccess)
|
||||
{
|
||||
*aSuccess = false;
|
||||
#ifdef MOZ_VALGRIND
|
||||
// Zero this so that Valgrind doesn't complain when we send it to another
|
||||
// process.
|
||||
memset(aRetVal, 0, sizeof(ScreenDetails));
|
||||
#endif
|
||||
|
||||
// Find the mWidget associated with the tabparent, and then return
|
||||
// the nsIScreen it's on.
|
||||
ContentParent* cp = static_cast<ContentParent*>(this->Manager());
|
||||
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
|
||||
RefPtr<TabParent> tabParent =
|
||||
cpm->GetTopLevelTabParentByProcessAndTabId(cp->ChildID(), aTabId);
|
||||
if(!tabParent){
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWidget> widget = tabParent->GetWidget();
|
||||
|
||||
nsCOMPtr<nsIScreen> screen;
|
||||
if (widget && widget->GetNativeData(NS_NATIVE_WINDOW)) {
|
||||
mScreenMgr->ScreenForNativeWidget(widget->GetNativeData(NS_NATIVE_WINDOW),
|
||||
getter_AddRefs(screen));
|
||||
} else {
|
||||
nsresult rv = mScreenMgr->GetPrimaryScreen(getter_AddRefs(screen));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return IPC_OK();
|
||||
}
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(screen, IPC_OK());
|
||||
|
||||
ScreenDetails details;
|
||||
if (!ExtractScreenDetails(screen, details)) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
*aRetVal = details;
|
||||
*aSuccess = true;
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool
|
||||
ScreenManagerParent::ExtractScreenDetails(nsIScreen* aScreen, ScreenDetails &aDetails)
|
||||
{
|
||||
if (!aScreen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t id;
|
||||
nsresult rv = aScreen->GetId(&id);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
aDetails.id() = id;
|
||||
|
||||
nsIntRect rect;
|
||||
rv = aScreen->GetRect(&rect.x, &rect.y, &rect.width, &rect.height);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
aDetails.rect() = rect;
|
||||
|
||||
nsIntRect rectDisplayPix;
|
||||
rv = aScreen->GetRectDisplayPix(&rectDisplayPix.x, &rectDisplayPix.y,
|
||||
&rectDisplayPix.width, &rectDisplayPix.height);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
aDetails.rectDisplayPix() = rectDisplayPix;
|
||||
|
||||
nsIntRect availRect;
|
||||
rv = aScreen->GetAvailRect(&availRect.x, &availRect.y, &availRect.width,
|
||||
&availRect.height);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
aDetails.availRect() = availRect;
|
||||
|
||||
nsIntRect availRectDisplayPix;
|
||||
rv = aScreen->GetAvailRectDisplayPix(&availRectDisplayPix.x,
|
||||
&availRectDisplayPix.y,
|
||||
&availRectDisplayPix.width,
|
||||
&availRectDisplayPix.height);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
aDetails.availRectDisplayPix() = availRectDisplayPix;
|
||||
|
||||
int32_t pixelDepth = 0;
|
||||
rv = aScreen->GetPixelDepth(&pixelDepth);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
aDetails.pixelDepth() = pixelDepth;
|
||||
|
||||
int32_t colorDepth = 0;
|
||||
rv = aScreen->GetColorDepth(&colorDepth);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
aDetails.colorDepth() = colorDepth;
|
||||
|
||||
double contentsScaleFactor = 1.0;
|
||||
rv = aScreen->GetContentsScaleFactor(&contentsScaleFactor);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
aDetails.contentsScaleFactor() = contentsScaleFactor;
|
||||
|
||||
double defaultCSSScaleFactor = 1.0;
|
||||
rv = aScreen->GetDefaultCSSScaleFactor(&defaultCSSScaleFactor);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
aDetails.defaultCSSScaleFactor() = defaultCSSScaleFactor;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ScreenManagerParent::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
/* -*- 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_dom_ScreenManagerParent_h
|
||||
#define mozilla_dom_ScreenManagerParent_h
|
||||
|
||||
#include "mozilla/dom/PScreenManagerParent.h"
|
||||
#include "nsIScreenManager.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ScreenManagerParent : public PScreenManagerParent
|
||||
{
|
||||
public:
|
||||
ScreenManagerParent(uint32_t* aNumberOfScreens,
|
||||
float* aSystemDefaultScale,
|
||||
bool* aSuccess);
|
||||
~ScreenManagerParent() {};
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvRefresh(uint32_t* aNumberOfScreens,
|
||||
float* aSystemDefaultScale,
|
||||
bool* aSuccess) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvScreenRefresh(const uint32_t& aId,
|
||||
ScreenDetails* aRetVal,
|
||||
bool* aSuccess) override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvGetPrimaryScreen(ScreenDetails* aRetVal,
|
||||
bool* aSuccess) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvScreenForRect(const int32_t& aLeft,
|
||||
const int32_t& aTop,
|
||||
const int32_t& aWidth,
|
||||
const int32_t& aHeight,
|
||||
ScreenDetails* aRetVal,
|
||||
bool* aSuccess) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvScreenForBrowser(const TabId& aTabId,
|
||||
ScreenDetails* aRetVal,
|
||||
bool* aSuccess) override;
|
||||
|
||||
private:
|
||||
bool ExtractScreenDetails(nsIScreen* aScreen, ScreenDetails &aDetails);
|
||||
nsCOMPtr<nsIScreenManager> mScreenMgr;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_ScreenManagerParent_h
|
|
@ -65,7 +65,6 @@ UNIFIED_SOURCES += [
|
|||
'PermissionMessageUtils.cpp',
|
||||
'PreallocatedProcessManager.cpp',
|
||||
'ProcessPriorityManager.cpp',
|
||||
'ScreenManagerParent.cpp',
|
||||
'StructuredCloneData.cpp',
|
||||
'TabChild.cpp',
|
||||
'TabContext.cpp',
|
||||
|
@ -97,7 +96,6 @@ IPDL_SOURCES += [
|
|||
'PFilePicker.ipdl',
|
||||
'PPluginWidget.ipdl',
|
||||
'PProcessHangMonitor.ipdl',
|
||||
'PScreenManager.ipdl',
|
||||
'PTabContext.ipdlh',
|
||||
'PURLClassifier.ipdl',
|
||||
'PURLClassifierInfo.ipdlh',
|
||||
|
|
|
@ -170,6 +170,8 @@ private:
|
|||
DECL_MEDIA_PREF("media.rust.test_mode", RustTestMode, bool, false);
|
||||
#endif
|
||||
|
||||
DECL_MEDIA_PREF("media.rust.mp4parser", EnableRustMP4Parser, bool, false);
|
||||
|
||||
public:
|
||||
// Manage the singleton:
|
||||
static MediaPrefs& GetSingleton();
|
||||
|
|
|
@ -1172,12 +1172,7 @@ NPBool nsPluginInstanceOwner::ConvertPointNoPuppet(nsIWidget *widget,
|
|||
double scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/
|
||||
presContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
|
||||
|
||||
nsCOMPtr<nsIScreenManager> screenMgr = do_GetService("@mozilla.org/gfx/screenmanager;1");
|
||||
if (!screenMgr) {
|
||||
return false;
|
||||
}
|
||||
nsCOMPtr<nsIScreen> screen;
|
||||
screenMgr->ScreenForNativeWidget(widget->GetNativeData(NS_NATIVE_WINDOW), getter_AddRefs(screen));
|
||||
nsCOMPtr<nsIScreen> screen = widget->GetWidgetScreen();
|
||||
if (!screen) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -609,21 +609,8 @@ nsDeviceContext::FindScreen(nsIScreen** outScreen)
|
|||
|
||||
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
|
||||
nsCOMPtr<nsIScreen> screen = mWidget->GetWidgetScreen();
|
||||
screen.forget(outScreen);
|
||||
|
||||
if (!(*outScreen)) {
|
||||
mScreenManager->GetPrimaryScreen(outScreen);
|
||||
|
|
|
@ -36,7 +36,7 @@ public:
|
|||
|
||||
// construct a wrapper around the specified drawable with dpy/format,
|
||||
// and known width/height.
|
||||
gfxXlibSurface(Screen *screen, Drawable drawable, XRenderPictFormat *format,
|
||||
gfxXlibSurface(::Screen *screen, Drawable drawable, XRenderPictFormat *format,
|
||||
const mozilla::gfx::IntSize& size);
|
||||
|
||||
explicit gfxXlibSurface(cairo_surface_t *csurf);
|
||||
|
@ -46,13 +46,13 @@ public:
|
|||
// the pixmap should be in video or system memory. It must be on
|
||||
// |screen| (if specified).
|
||||
static already_AddRefed<gfxXlibSurface>
|
||||
Create(Screen *screen, Visual *visual, const mozilla::gfx::IntSize& size,
|
||||
Create(::Screen *screen, Visual *visual, const mozilla::gfx::IntSize& size,
|
||||
Drawable relatedDrawable = X11None);
|
||||
static cairo_surface_t *
|
||||
CreateCairoSurface(Screen *screen, Visual *visual, const mozilla::gfx::IntSize& size,
|
||||
CreateCairoSurface(::Screen *screen, Visual *visual, const mozilla::gfx::IntSize& size,
|
||||
Drawable relatedDrawable = X11None);
|
||||
static already_AddRefed<gfxXlibSurface>
|
||||
Create(Screen* screen, XRenderPictFormat *format, const mozilla::gfx::IntSize& size,
|
||||
Create(::Screen* screen, XRenderPictFormat *format, const mozilla::gfx::IntSize& size,
|
||||
Drawable relatedDrawable = X11None);
|
||||
|
||||
virtual ~gfxXlibSurface();
|
||||
|
@ -65,12 +65,12 @@ public:
|
|||
virtual const mozilla::gfx::IntSize GetSize() const override;
|
||||
|
||||
Display* XDisplay() { return mDisplay; }
|
||||
Screen* XScreen();
|
||||
::Screen* XScreen();
|
||||
Drawable XDrawable() { return mDrawable; }
|
||||
XRenderPictFormat* XRenderFormat();
|
||||
|
||||
static int DepthOfVisual(const Screen* screen, const Visual* visual);
|
||||
static Visual* FindVisual(Screen* screen, gfxImageFormat format);
|
||||
static int DepthOfVisual(const ::Screen* screen, const Visual* visual);
|
||||
static Visual* FindVisual(::Screen* screen, gfxImageFormat format);
|
||||
static XRenderPictFormat *FindRenderFormat(Display *dpy, gfxImageFormat format);
|
||||
static bool GetColormapAndVisual(cairo_surface_t* aXlibSurface, Colormap* colormap, Visual **visual);
|
||||
|
||||
|
|
|
@ -71,7 +71,6 @@
|
|||
#include "nsThreadUtils.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "OrientationObserver.h"
|
||||
#include "UeventPoller.h"
|
||||
#include "nsIWritablePropertyBag2.h"
|
||||
#include <algorithm>
|
||||
|
@ -1012,13 +1011,12 @@ GetCurrentScreenConfiguration(hal::ScreenConfiguration* aScreenConfiguration)
|
|||
bool
|
||||
LockScreenOrientation(const dom::ScreenOrientationInternal& aOrientation)
|
||||
{
|
||||
return OrientationObserver::GetInstance()->LockScreenOrientation(aOrientation);
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
UnlockScreenOrientation()
|
||||
{
|
||||
OrientationObserver::GetInstance()->UnlockScreenOrientation();
|
||||
}
|
||||
|
||||
// This thread will wait for the alarm firing by a blocking IO.
|
||||
|
|
|
@ -884,8 +884,6 @@ description =
|
|||
description =
|
||||
[PContent::IsSecureURI]
|
||||
description =
|
||||
[PContent::PScreenManager]
|
||||
description =
|
||||
[PContent::PURLClassifier]
|
||||
description =
|
||||
[PContent::ClassifyLocal]
|
||||
|
@ -934,16 +932,6 @@ description =
|
|||
description =
|
||||
[PContentBridge::SyncMessage]
|
||||
description =
|
||||
[PScreenManager::Refresh]
|
||||
description =
|
||||
[PScreenManager::ScreenRefresh]
|
||||
description =
|
||||
[PScreenManager::GetPrimaryScreen]
|
||||
description =
|
||||
[PScreenManager::ScreenForRect]
|
||||
description =
|
||||
[PScreenManager::ScreenForBrowser]
|
||||
description =
|
||||
[PGMP::StartPlugin]
|
||||
description =
|
||||
[PGMPService::LaunchGMP]
|
||||
|
|
|
@ -603,10 +603,10 @@ GetMinAndMaxScaleForAnimationProperty(const nsIFrame* aFrame,
|
|||
for (const AnimationPropertySegment& segment : prop.mSegments) {
|
||||
// In case of add or accumulate composite, StyleAnimationValue does
|
||||
// not have a valid value.
|
||||
if (segment.HasReplacableFromValue()) {
|
||||
if (segment.HasReplaceableFromValue()) {
|
||||
UpdateMinMaxScale(aFrame, segment.mFromValue, aMinScale, aMaxScale);
|
||||
}
|
||||
if (segment.HasReplacableToValue()) {
|
||||
if (segment.HasReplaceableToValue()) {
|
||||
UpdateMinMaxScale(aFrame, segment.mToValue, aMinScale, aMaxScale);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -675,7 +675,9 @@ void nsTextControlFrame::SetFocus(bool aOn, bool aRepaint)
|
|||
}
|
||||
if (!(lastFocusMethod & nsIFocusManager::FLAG_BYMOUSE)) {
|
||||
RefPtr<ScrollOnFocusEvent> event = new ScrollOnFocusEvent(this);
|
||||
nsresult rv = NS_DispatchToCurrentThread(event);
|
||||
nsresult rv = mContent->OwnerDoc()->Dispatch("ScrollOnFocusEvent",
|
||||
TaskCategory::Other,
|
||||
do_AddRef(event));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mScrollEvent = event;
|
||||
}
|
||||
|
|
|
@ -365,9 +365,6 @@ to mochitest command.
|
|||
* test_variables.html `--weird`: name of custom property is not escaped properly servo/servo#15399 [1]
|
||||
* image-layer values should omit some of its parts when they are initial servo/servo#15951
|
||||
* test_shorthand_property_getters.html `background` [2]
|
||||
* counter-{reset,increment} doesn't serialize none servo/servo#15977
|
||||
* test_value_storage.html `counter-reset` [2]
|
||||
* test_value_storage.html `counter-increment` [2]
|
||||
* :not(*) doesn't serialize properly servo/servo#16017
|
||||
* test_selectors.html `:not()` [8]
|
||||
* ... `:not(html|)` [1]
|
||||
|
@ -410,7 +407,6 @@ to mochitest command.
|
|||
* ... `perspective'`: servo/servo#15449 [20]
|
||||
* ... `'text-shadow'`: third length of text-shadow servo/servo#15999 [2]
|
||||
* ... `flex-basis`: servo/servo#15902 [6]
|
||||
* ... `border-image-slice`: servo/servo#15339 [2]
|
||||
* Quirks mode support
|
||||
* hashless color servo/servo#15341
|
||||
* test_property_syntax_errors.html `color: 000000` [22]
|
||||
|
|
|
@ -230,7 +230,7 @@ IndiceWrapperRust::GetIndice(size_t aIndex, Index::Indice& aIndice) const
|
|||
MP4Metadata::MP4Metadata(Stream* aSource)
|
||||
: mStagefright(MakeUnique<MP4MetadataStagefright>(aSource))
|
||||
, mRust(MakeUnique<MP4MetadataRust>(aSource))
|
||||
, mPreferRust(false)
|
||||
, mPreferRust(MediaPrefs::EnableRustMP4Parser())
|
||||
, mReportedAudioTrackTelemetry(false)
|
||||
, mReportedVideoTrackTelemetry(false)
|
||||
#ifndef RELEASE_OR_BETA
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "gtest/gtest.h"
|
||||
#include "MediaData.h"
|
||||
#include "MediaPrefs.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mp4_demuxer/BufferStream.h"
|
||||
#include "mp4_demuxer/MP4Metadata.h"
|
||||
|
@ -205,10 +206,64 @@ static const TestFileData testFiles[] = {
|
|||
false, 0, false, false, 2 },
|
||||
};
|
||||
|
||||
static const TestFileData rustTestFiles[] = {
|
||||
// filename #V dur w h #A dur crypt off moof headr audio_profile
|
||||
{ "test_case_1156505.mp4", 0, -1, 0, 0, 0, -1, false, 152, false, false, 0 },
|
||||
{ "test_case_1181213.mp4", 1, 416666,
|
||||
320, 240, 1, 477460,
|
||||
true, 0, false, false, 2 },
|
||||
{ "test_case_1181215.mp4", 0, -1, 0, 0, 0, -1, false, 0, false, false, 0 },
|
||||
{ "test_case_1181220.mp4", 0, -1, 0, 0, 0, -1, false, 0, false, false, 0 },
|
||||
{ "test_case_1181223.mp4", 1, 416666,
|
||||
320, 240, 0, -1, false, 0, false, false, 0 },
|
||||
{ "test_case_1181719.mp4", 0, -1, 0, 0, 0, -1, false, 0, false, false, 0 },
|
||||
{ "test_case_1185230.mp4", 2, 416666,
|
||||
320, 240, 2, 5, false, 0, false, false, 2 },
|
||||
{ "test_case_1187067.mp4", 1, 80000,
|
||||
160, 90, 0, -1, false, 0, false, false, 0 },
|
||||
{ "test_case_1200326.mp4", 0, -1, 0, 0, 0, -1, false, 0, false, false, 0 },
|
||||
{ "test_case_1204580.mp4", 1, 502500,
|
||||
320, 180, 0, -1, false, 0, false, false, 0 },
|
||||
{ "test_case_1216748.mp4", 0, -1, 0, 0, 0, -1, false, 152, false, false, 0 },
|
||||
{ "test_case_1296473.mp4", 0, -1, 0, 0, 0, -1, false, 0, false, false, 0 },
|
||||
{ "test_case_1296532.mp4", 1, 5589333,
|
||||
560, 320, 1, 5589333,
|
||||
true, 0, true, true, 2 },
|
||||
{ "test_case_1301065.mp4", 0, -1, 0, 0, 1, 100079991719000000,
|
||||
false, 0, false, false, 2 },
|
||||
{ "test_case_1301065-u32max.mp4", 0, -1, 0, 0, 1, 97391548639,
|
||||
false, 0, false, false, 2 },
|
||||
{ "test_case_1301065-max-ez.mp4", 0, -1, 0, 0, 1, 209146758205306,
|
||||
false, 0, false, false, 2 },
|
||||
{ "test_case_1301065-harder.mp4", 0, -1, 0, 0, 1, 209146758205328,
|
||||
false, 0, false, false, 2 },
|
||||
{ "test_case_1301065-max-ok.mp4", 0, -1, 0, 0, 1, 9223372036854775804,
|
||||
false, 0, false, false, 2 },
|
||||
// The duration is overflow for int64_t in TestFileData, rust parser uses uint64_t so
|
||||
// this file is ignore.
|
||||
//{ "test_case_1301065-overfl.mp4", 0, -1, 0, 0, 1, 9223372036854775827,
|
||||
// false, 0, false, false, 2 },
|
||||
{ "test_case_1301065-i64max.mp4", 0, -1, 0, 0, 0, -1, false, 0, false, false, 0 },
|
||||
{ "test_case_1301065-i64min.mp4", 0, -1, 0, 0, 0, -1, false, 0, false, false, 0 },
|
||||
{ "test_case_1301065-u64max.mp4", 0, -1, 0, 0, 1, 0, false, 0, false, false, 2 },
|
||||
{ "test_case_1329061.mov", 0, -1, 0, 0, 1, 234567981,
|
||||
false, 0, false, false, 2 },
|
||||
};
|
||||
TEST(stagefright_MPEG4Metadata, test_case_mp4)
|
||||
{
|
||||
for (size_t test = 0; test < ArrayLength(testFiles); ++test) {
|
||||
nsTArray<uint8_t> buffer = ReadTestFile(testFiles[test].mFilename);
|
||||
const TestFileData* tests = nullptr;
|
||||
size_t length = 0;
|
||||
|
||||
if (MediaPrefs::EnableRustMP4Parser()) {
|
||||
tests = rustTestFiles;
|
||||
length = ArrayLength(rustTestFiles);
|
||||
} else {
|
||||
tests = testFiles;
|
||||
length = ArrayLength(testFiles);
|
||||
}
|
||||
|
||||
for (size_t test = 0; test < length; ++test) {
|
||||
nsTArray<uint8_t> buffer = ReadTestFile(tests[test].mFilename);
|
||||
ASSERT_FALSE(buffer.IsEmpty());
|
||||
RefPtr<Stream> stream = new TestStream(buffer.Elements(), buffer.Length());
|
||||
|
||||
|
@ -217,15 +272,15 @@ TEST(stagefright_MPEG4Metadata, test_case_mp4)
|
|||
|
||||
MP4Metadata metadata(stream);
|
||||
EXPECT_EQ(0u, metadata.GetNumberTracks(TrackInfo::kUndefinedTrack));
|
||||
EXPECT_EQ(testFiles[test].mNumberAudioTracks,
|
||||
EXPECT_EQ(tests[test].mNumberAudioTracks,
|
||||
metadata.GetNumberTracks(TrackInfo::kAudioTrack));
|
||||
EXPECT_EQ(testFiles[test].mNumberVideoTracks,
|
||||
EXPECT_EQ(tests[test].mNumberVideoTracks,
|
||||
metadata.GetNumberTracks(TrackInfo::kVideoTrack));
|
||||
EXPECT_EQ(0u, metadata.GetNumberTracks(TrackInfo::kTextTrack));
|
||||
EXPECT_EQ(0u, metadata.GetNumberTracks(static_cast<TrackInfo::TrackType>(-1)));
|
||||
EXPECT_FALSE(metadata.GetTrackInfo(TrackInfo::kUndefinedTrack, 0));
|
||||
UniquePtr<TrackInfo> trackInfo = metadata.GetTrackInfo(TrackInfo::kVideoTrack, 0);
|
||||
if (testFiles[test].mNumberVideoTracks == 0) {
|
||||
if (tests[test].mNumberVideoTracks == 0) {
|
||||
EXPECT_TRUE(!trackInfo);
|
||||
} else {
|
||||
ASSERT_TRUE(!!trackInfo);
|
||||
|
@ -233,9 +288,9 @@ TEST(stagefright_MPEG4Metadata, test_case_mp4)
|
|||
ASSERT_TRUE(!!videoInfo);
|
||||
EXPECT_TRUE(videoInfo->IsValid());
|
||||
EXPECT_TRUE(videoInfo->IsVideo());
|
||||
EXPECT_EQ(testFiles[test].mVideoDuration, videoInfo->mDuration);
|
||||
EXPECT_EQ(testFiles[test].mWidth, videoInfo->mDisplay.width);
|
||||
EXPECT_EQ(testFiles[test].mHeight, videoInfo->mDisplay.height);
|
||||
EXPECT_EQ(tests[test].mVideoDuration, videoInfo->mDuration);
|
||||
EXPECT_EQ(tests[test].mWidth, videoInfo->mDisplay.width);
|
||||
EXPECT_EQ(tests[test].mHeight, videoInfo->mDisplay.height);
|
||||
|
||||
UniquePtr<IndiceWrapper> indices = metadata.GetTrackIndice(videoInfo->mTrackId);
|
||||
EXPECT_TRUE(!!indices);
|
||||
|
@ -247,7 +302,7 @@ TEST(stagefright_MPEG4Metadata, test_case_mp4)
|
|||
}
|
||||
}
|
||||
trackInfo = metadata.GetTrackInfo(TrackInfo::kAudioTrack, 0);
|
||||
if (testFiles[test].mNumberAudioTracks == 0) {
|
||||
if (tests[test].mNumberAudioTracks == 0) {
|
||||
EXPECT_TRUE(!trackInfo);
|
||||
} else {
|
||||
ASSERT_TRUE(!!trackInfo);
|
||||
|
@ -255,8 +310,11 @@ TEST(stagefright_MPEG4Metadata, test_case_mp4)
|
|||
ASSERT_TRUE(!!audioInfo);
|
||||
EXPECT_TRUE(audioInfo->IsValid());
|
||||
EXPECT_TRUE(audioInfo->IsAudio());
|
||||
EXPECT_EQ(testFiles[test].mAudioDuration, audioInfo->mDuration);
|
||||
EXPECT_EQ(testFiles[test].mAudioProfile, audioInfo->mProfile);
|
||||
EXPECT_EQ(tests[test].mAudioDuration, audioInfo->mDuration);
|
||||
EXPECT_EQ(tests[test].mAudioProfile, audioInfo->mProfile);
|
||||
if (tests[test].mAudioDuration != audioInfo->mDuration) {
|
||||
MOZ_RELEASE_ASSERT(false);
|
||||
}
|
||||
|
||||
UniquePtr<IndiceWrapper> indices = metadata.GetTrackIndice(audioInfo->mTrackId);
|
||||
EXPECT_TRUE(!!indices);
|
||||
|
@ -264,14 +322,14 @@ TEST(stagefright_MPEG4Metadata, test_case_mp4)
|
|||
Index::Indice data;
|
||||
EXPECT_TRUE(indices->GetIndice(i, data));
|
||||
EXPECT_TRUE(data.start_offset <= data.end_offset);
|
||||
EXPECT_TRUE(data.start_composition <= data.end_composition);
|
||||
EXPECT_TRUE(int64_t(data.start_composition) <= int64_t(data.end_composition));
|
||||
}
|
||||
}
|
||||
EXPECT_FALSE(metadata.GetTrackInfo(TrackInfo::kTextTrack, 0));
|
||||
EXPECT_FALSE(metadata.GetTrackInfo(static_cast<TrackInfo::TrackType>(-1), 0));
|
||||
// We can see anywhere in any MPEG4.
|
||||
EXPECT_TRUE(metadata.CanSeek());
|
||||
EXPECT_EQ(testFiles[test].mHasCrypto, metadata.Crypto().valid);
|
||||
EXPECT_EQ(tests[test].mHasCrypto, metadata.Crypto().valid);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -315,8 +373,19 @@ TEST(stagefright_MPEG4Metadata, test_case_mp4_subsets)
|
|||
|
||||
TEST(stagefright_MoofParser, test_case_mp4)
|
||||
{
|
||||
for (size_t test = 0; test < ArrayLength(testFiles); ++test) {
|
||||
nsTArray<uint8_t> buffer = ReadTestFile(testFiles[test].mFilename);
|
||||
const TestFileData* tests = nullptr;
|
||||
size_t length = 0;
|
||||
|
||||
if (MediaPrefs::EnableRustMP4Parser()) {
|
||||
tests = rustTestFiles;
|
||||
length = ArrayLength(rustTestFiles);
|
||||
} else {
|
||||
tests = testFiles;
|
||||
length = ArrayLength(testFiles);
|
||||
}
|
||||
|
||||
for (size_t test = 0; test < length; ++test) {
|
||||
nsTArray<uint8_t> buffer = ReadTestFile(tests[test].mFilename);
|
||||
ASSERT_FALSE(buffer.IsEmpty());
|
||||
RefPtr<Stream> stream = new TestStream(buffer.Elements(), buffer.Length());
|
||||
|
||||
|
@ -332,20 +401,20 @@ TEST(stagefright_MoofParser, test_case_mp4)
|
|||
EXPECT_FALSE(parser.mInitRange.IsEmpty());
|
||||
const MediaByteRangeSet byteRanges(
|
||||
MediaByteRange(0, int64_t(buffer.Length())));
|
||||
EXPECT_EQ(testFiles[test].mValidMoof,
|
||||
EXPECT_EQ(tests[test].mValidMoof,
|
||||
parser.RebuildFragmentedIndex(byteRanges));
|
||||
if (testFiles[test].mMoofReachedOffset == 0) {
|
||||
if (tests[test].mMoofReachedOffset == 0) {
|
||||
EXPECT_EQ(buffer.Length(), parser.mOffset);
|
||||
EXPECT_TRUE(parser.ReachedEnd());
|
||||
} else {
|
||||
EXPECT_EQ(testFiles[test].mMoofReachedOffset, parser.mOffset);
|
||||
EXPECT_EQ(tests[test].mMoofReachedOffset, parser.mOffset);
|
||||
EXPECT_FALSE(parser.ReachedEnd());
|
||||
}
|
||||
|
||||
EXPECT_FALSE(parser.mInitRange.IsEmpty());
|
||||
EXPECT_TRUE(parser.GetCompositionRange(byteRanges).IsNull());
|
||||
EXPECT_TRUE(parser.FirstCompleteMediaSegment().IsEmpty());
|
||||
EXPECT_EQ(testFiles[test].mHeader,
|
||||
EXPECT_EQ(tests[test].mHeader,
|
||||
!parser.FirstCompleteMediaHeader().IsEmpty());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -313,8 +313,6 @@ public class MediaControlService extends Service implements Tabs.OnTabsChangedLi
|
|||
super.onPlay();
|
||||
setState(State.PLAYING);
|
||||
notifyObservers("MediaControl", "resumeMedia");
|
||||
// To make sure we always own audio focus during playing.
|
||||
AudioFocusAgent.notifyStartedPlaying();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -323,7 +321,6 @@ public class MediaControlService extends Service implements Tabs.OnTabsChangedLi
|
|||
super.onPause();
|
||||
setState(State.PAUSED);
|
||||
notifyObservers("MediaControl", "mediaControlPaused");
|
||||
AudioFocusAgent.notifyStoppedPlaying();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1060,16 +1060,6 @@ public class GeckoAppShell
|
|||
vibrator().cancel();
|
||||
}
|
||||
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
private static void setKeepScreenOn(final boolean on) {
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// TODO
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
private static boolean isNetworkLinkUp() {
|
||||
ConnectivityManager cm = (ConnectivityManager)
|
||||
|
|
|
@ -135,6 +135,14 @@ dependencies = [
|
|||
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.0.0-alpha2"
|
||||
|
@ -284,7 +292,7 @@ dependencies = [
|
|||
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"offscreen_gl_context 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo_config 0.0.1",
|
||||
"webrender_traits 0.26.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.27.0 (git+https://github.com/servo/webrender)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -298,7 +306,7 @@ dependencies = [
|
|||
"ipc-channel 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender_traits 0.26.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.27.0 (git+https://github.com/servo/webrender)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -419,8 +427,8 @@ dependencies = [
|
|||
"servo_url 0.0.1",
|
||||
"style_traits 0.0.1",
|
||||
"time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender 0.25.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.26.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender 0.26.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.27.0 (git+https://github.com/servo/webrender)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -453,7 +461,7 @@ dependencies = [
|
|||
"servo_remutex 0.0.1",
|
||||
"servo_url 0.0.1",
|
||||
"style_traits 0.0.1",
|
||||
"webrender_traits 0.26.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.27.0 (git+https://github.com/servo/webrender)",
|
||||
"webvr_traits 0.0.1",
|
||||
]
|
||||
|
||||
|
@ -698,7 +706,7 @@ dependencies = [
|
|||
"servo_geometry 0.0.1",
|
||||
"servo_url 0.0.1",
|
||||
"style_traits 0.0.1",
|
||||
"webrender_traits 0.26.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.27.0 (git+https://github.com/servo/webrender)",
|
||||
"x11 2.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -980,7 +988,7 @@ dependencies = [
|
|||
"time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"truetype 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender_traits 0.26.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.27.0 (git+https://github.com/servo/webrender)",
|
||||
"xi-unicode 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -1059,7 +1067,7 @@ dependencies = [
|
|||
"servo_url 0.0.1",
|
||||
"style_traits 0.0.1",
|
||||
"user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender_traits 0.26.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.27.0 (git+https://github.com/servo/webrender)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"x11 2.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -1370,7 +1378,7 @@ dependencies = [
|
|||
"style_traits 0.0.1",
|
||||
"unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender_traits 0.26.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.27.0 (git+https://github.com/servo/webrender)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1410,7 +1418,7 @@ dependencies = [
|
|||
"servo_geometry 0.0.1",
|
||||
"servo_url 0.0.1",
|
||||
"style 0.0.1",
|
||||
"webrender_traits 0.26.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.27.0 (git+https://github.com/servo/webrender)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1424,7 +1432,7 @@ dependencies = [
|
|||
"profile_traits 0.0.1",
|
||||
"script_traits 0.0.1",
|
||||
"servo_url 0.0.1",
|
||||
"webrender_traits 0.26.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.27.0 (git+https://github.com/servo/webrender)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1509,8 +1517,8 @@ dependencies = [
|
|||
"style 0.0.1",
|
||||
"style_traits 0.0.1",
|
||||
"webdriver_server 0.0.1",
|
||||
"webrender 0.25.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.26.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender 0.26.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.27.0 (git+https://github.com/servo/webrender)",
|
||||
"webvr 0.0.1",
|
||||
"webvr_traits 0.0.1",
|
||||
]
|
||||
|
@ -1659,7 +1667,7 @@ dependencies = [
|
|||
"heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender_traits 0.26.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.27.0 (git+https://github.com/servo/webrender)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1671,6 +1679,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
name = "net"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"base64 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"brotli 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"devtools_traits 0.0.1",
|
||||
|
@ -1688,7 +1697,6 @@ dependencies = [
|
|||
"openssl 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl-verify 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"profile_traits 0.0.1",
|
||||
"rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1701,7 +1709,7 @@ dependencies = [
|
|||
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uuid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender_traits 0.26.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.27.0 (git+https://github.com/servo/webrender)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1759,7 +1767,7 @@ dependencies = [
|
|||
"servo_url 0.0.1",
|
||||
"url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uuid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender_traits 0.26.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.27.0 (git+https://github.com/servo/webrender)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2241,6 +2249,7 @@ dependencies = [
|
|||
"app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"audio-video-metadata 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"base64 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bluetooth_traits 0.0.1",
|
||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2285,7 +2294,6 @@ dependencies = [
|
|||
"ref_filter_map 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ref_slice 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"script_layout_interface 0.0.1",
|
||||
"script_plugins 0.0.1",
|
||||
"script_traits 0.0.1",
|
||||
|
@ -2304,7 +2312,7 @@ dependencies = [
|
|||
"tinyfiledialogs 2.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uuid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender_traits 0.26.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.27.0 (git+https://github.com/servo/webrender)",
|
||||
"webvr 0.0.1",
|
||||
"webvr_traits 0.0.1",
|
||||
"xml5ever 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3157,6 +3165,7 @@ dependencies = [
|
|||
name = "webdriver_server"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"base64 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper 0.9.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3177,8 +3186,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "webrender"
|
||||
version = "0.25.0"
|
||||
source = "git+https://github.com/servo/webrender#0794911f97cae92496fca992d7430da696fa24eb"
|
||||
version = "0.26.0"
|
||||
source = "git+https://github.com/servo/webrender#b2dd9f792d0cb3dfc591567c105755f56f35956d"
|
||||
dependencies = [
|
||||
"app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bincode 1.0.0-alpha2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3200,13 +3209,13 @@ dependencies = [
|
|||
"thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"threadpool 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender_traits 0.26.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.27.0 (git+https://github.com/servo/webrender)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webrender_traits"
|
||||
version = "0.26.0"
|
||||
source = "git+https://github.com/servo/webrender#0794911f97cae92496fca992d7430da696fa24eb"
|
||||
version = "0.27.0"
|
||||
source = "git+https://github.com/servo/webrender#b2dd9f792d0cb3dfc591567c105755f56f35956d"
|
||||
dependencies = [
|
||||
"app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3230,7 +3239,7 @@ dependencies = [
|
|||
"msg 0.0.1",
|
||||
"script_traits 0.0.1",
|
||||
"servo_config 0.0.1",
|
||||
"webrender_traits 0.26.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.27.0 (git+https://github.com/servo/webrender)",
|
||||
"webvr_traits 0.0.1",
|
||||
]
|
||||
|
||||
|
@ -3336,6 +3345,7 @@ dependencies = [
|
|||
"checksum azure 0.15.0 (git+https://github.com/servo/rust-azure)" = "<none>"
|
||||
"checksum backtrace 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f551bc2ddd53aea015d453ef0b635af89444afa5ed2405dd0b2062ad5d600d80"
|
||||
"checksum backtrace-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d192fd129132fbc97497c1f2ec2c2c5174e376b95f535199ef4fe0a293d33842"
|
||||
"checksum base64 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9892882c3bd89ed02dec391c128984c772b663a29700c32b5de0b33861cdf2bd"
|
||||
"checksum bincode 1.0.0-alpha2 (registry+https://github.com/rust-lang/crates.io-index)" = "62650bb5651ba8f0580cebf4ef255d791b8b0ef53800322661e1bb5791d42966"
|
||||
"checksum bindgen 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "facc480c409c373db3c870e377ce223e5e07d979efc2604691dc6f583e8ded0f"
|
||||
"checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c"
|
||||
|
@ -3572,8 +3582,8 @@ dependencies = [
|
|||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff"
|
||||
"checksum webdriver 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdc28802daddee94267a657ffeac2593a33881fb7a3a44fedd320b1319efcaf6"
|
||||
"checksum webrender 0.25.0 (git+https://github.com/servo/webrender)" = "<none>"
|
||||
"checksum webrender_traits 0.26.0 (git+https://github.com/servo/webrender)" = "<none>"
|
||||
"checksum webrender 0.26.0 (git+https://github.com/servo/webrender)" = "<none>"
|
||||
"checksum webrender_traits 0.27.0 (git+https://github.com/servo/webrender)" = "<none>"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"checksum ws 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "04614a58714f3fd4a8b1da4bcae9f031c532d35988c3d39627619248113f8be8"
|
||||
|
|
|
@ -567,7 +567,8 @@ impl<'a> CanvasPaintThread<'a> {
|
|||
offset: 0,
|
||||
is_opaque: false,
|
||||
},
|
||||
element.into());
|
||||
element.into(),
|
||||
None);
|
||||
|
||||
let data = CanvasImageData {
|
||||
image_key: self.webrender_image_key,
|
||||
|
|
|
@ -261,7 +261,8 @@ impl WebGLPaintThread {
|
|||
offset: 0,
|
||||
is_opaque: false,
|
||||
},
|
||||
pixels.clone());
|
||||
pixels.clone(),
|
||||
None);
|
||||
|
||||
let image_data = CanvasImageData {
|
||||
image_key: image_key,
|
||||
|
|
|
@ -886,10 +886,7 @@ pub struct IframeDisplayItem {
|
|||
|
||||
/// Paints a gradient.
|
||||
#[derive(Clone, Deserialize, HeapSizeOf, Serialize)]
|
||||
pub struct GradientDisplayItem {
|
||||
/// Fields common to all display items.
|
||||
pub base: BaseDisplayItem,
|
||||
|
||||
pub struct Gradient {
|
||||
/// The start point of the gradient (computed during display list construction).
|
||||
pub start_point: Point2D<Au>,
|
||||
|
||||
|
@ -900,6 +897,15 @@ pub struct GradientDisplayItem {
|
|||
pub stops: Vec<GradientStop>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, HeapSizeOf, Serialize)]
|
||||
pub struct GradientDisplayItem {
|
||||
/// Fields common to all display item.
|
||||
pub base: BaseDisplayItem,
|
||||
|
||||
/// Contains all gradient data. Included start, end point and color stops.
|
||||
pub gradient: Gradient,
|
||||
}
|
||||
|
||||
/// A normal border, supporting CSS border styles.
|
||||
#[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
|
||||
pub struct NormalBorder {
|
||||
|
@ -939,11 +945,22 @@ pub struct ImageBorder {
|
|||
pub repeat_vertical: webrender_traits::RepeatMode,
|
||||
}
|
||||
|
||||
/// A border that is made of linear gradient
|
||||
#[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
|
||||
pub struct GradientBorder {
|
||||
/// The gradient info that this border uses, border-image-source.
|
||||
pub gradient: Gradient,
|
||||
|
||||
/// Outsets for the border, as per border-image-outset.
|
||||
pub outset: SideOffsets2D<f32>,
|
||||
}
|
||||
|
||||
/// Specifies the type of border
|
||||
#[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
|
||||
pub enum BorderDetails {
|
||||
Normal(NormalBorder),
|
||||
Image(ImageBorder),
|
||||
Gradient(GradientBorder),
|
||||
}
|
||||
|
||||
/// Paints a border.
|
||||
|
|
|
@ -20,6 +20,7 @@ use flow::{BaseFlow, Flow, IS_ABSOLUTELY_POSITIONED};
|
|||
use flow_ref::FlowRef;
|
||||
use fragment::{CoordinateSystem, Fragment, ImageFragmentInfo, ScannedTextFragmentInfo};
|
||||
use fragment::{SpecificFragmentInfo, TruncatedFragmentInfo};
|
||||
use gfx::display_list;
|
||||
use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDetails};
|
||||
use gfx::display_list::{BorderDisplayItem, ImageBorder, NormalBorder};
|
||||
use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion};
|
||||
|
@ -350,6 +351,12 @@ pub trait FragmentDisplayListBuilding {
|
|||
image_url: &ServoUrl,
|
||||
background_index: usize);
|
||||
|
||||
fn convert_gradient(&self,
|
||||
absolute_bounds: &Rect<Au>,
|
||||
gradient: &Gradient,
|
||||
style: &ServoComputedValues)
|
||||
-> Option<display_list::Gradient>;
|
||||
|
||||
/// Adds the display items necessary to paint the background linear gradient of this fragment
|
||||
/// to the appropriate section of the display list.
|
||||
fn build_display_list_for_background_gradient(&self,
|
||||
|
@ -831,20 +838,13 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
fn build_display_list_for_background_gradient(&self,
|
||||
state: &mut DisplayListBuildState,
|
||||
display_list_section: DisplayListSection,
|
||||
absolute_bounds: &Rect<Au>,
|
||||
clip: &ClippingRegion,
|
||||
gradient: &Gradient,
|
||||
style: &ServoComputedValues) {
|
||||
let mut clip = clip.clone();
|
||||
clip.intersect_rect(absolute_bounds);
|
||||
|
||||
|
||||
fn convert_gradient(&self,
|
||||
absolute_bounds: &Rect<Au>,
|
||||
gradient: &Gradient,
|
||||
style: &ServoComputedValues) -> Option<display_list::Gradient> {
|
||||
// FIXME: Repeating gradients aren't implemented yet.
|
||||
if gradient.repeating {
|
||||
return;
|
||||
return None;
|
||||
}
|
||||
let angle = if let GradientKind::Linear(angle_or_corner) = gradient.gradient_kind {
|
||||
match angle_or_corner {
|
||||
|
@ -869,7 +869,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
}
|
||||
} else {
|
||||
// FIXME: Radial gradients aren't implemented yet.
|
||||
return;
|
||||
return None;
|
||||
};
|
||||
|
||||
// Get correct gradient line length, based on:
|
||||
|
@ -953,19 +953,39 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
let center = Point2D::new(absolute_bounds.origin.x + absolute_bounds.size.width / 2,
|
||||
absolute_bounds.origin.y + absolute_bounds.size.height / 2);
|
||||
|
||||
let base = state.create_base_display_item(absolute_bounds,
|
||||
&clip,
|
||||
self.node,
|
||||
style.get_cursor(Cursor::Default),
|
||||
display_list_section);
|
||||
let gradient_display_item = DisplayItem::Gradient(box GradientDisplayItem {
|
||||
base: base,
|
||||
Some(display_list::Gradient {
|
||||
start_point: center - delta,
|
||||
end_point: center + delta,
|
||||
stops: stops,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
state.add_display_item(gradient_display_item);
|
||||
fn build_display_list_for_background_gradient(&self,
|
||||
state: &mut DisplayListBuildState,
|
||||
display_list_section: DisplayListSection,
|
||||
absolute_bounds: &Rect<Au>,
|
||||
clip: &ClippingRegion,
|
||||
gradient: &Gradient,
|
||||
style: &ServoComputedValues) {
|
||||
let mut clip = clip.clone();
|
||||
clip.intersect_rect(absolute_bounds);
|
||||
|
||||
let grad = self.convert_gradient(absolute_bounds, gradient, style);
|
||||
|
||||
if let Some(x) = grad {
|
||||
let base = state.create_base_display_item(absolute_bounds,
|
||||
&clip,
|
||||
self.node,
|
||||
style.get_cursor(Cursor::Default),
|
||||
display_list_section);
|
||||
|
||||
let gradient_display_item = DisplayItem::Gradient(box GradientDisplayItem {
|
||||
base: base,
|
||||
gradient: x,
|
||||
});
|
||||
|
||||
state.add_display_item(gradient_display_item);
|
||||
}
|
||||
}
|
||||
|
||||
fn build_display_list_for_box_shadow_if_applicable(&self,
|
||||
|
@ -1076,8 +1096,28 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
}),
|
||||
}));
|
||||
}
|
||||
Some(computed::Image::Gradient(..)) => {
|
||||
// TODO(gw): Handle border-image with gradient.
|
||||
Some(computed::Image::Gradient(ref gradient)) => {
|
||||
match gradient.gradient_kind {
|
||||
GradientKind::Linear(_) => {
|
||||
let grad = self.convert_gradient(&bounds, gradient, style);
|
||||
|
||||
if let Some(x) = grad {
|
||||
state.add_display_item(DisplayItem::Border(box BorderDisplayItem {
|
||||
base: base,
|
||||
border_widths: border.to_physical(style.writing_mode),
|
||||
details: BorderDetails::Gradient(display_list::GradientBorder {
|
||||
gradient: x,
|
||||
|
||||
// TODO(gw): Support border-image-outset
|
||||
outset: SideOffsets2D::zero(),
|
||||
}),
|
||||
}));
|
||||
}
|
||||
}
|
||||
GradientKind::Radial(_, _) => {
|
||||
// TODO(gw): Handle border-image with radial gradient.
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(computed::Image::ImageRect(..)) => {
|
||||
// TODO: Handle border-image with `-moz-image-rect`.
|
||||
|
|
|
@ -351,20 +351,30 @@ impl WebRenderDisplayItemConverter for DisplayItem {
|
|||
}
|
||||
}
|
||||
}
|
||||
BorderDetails::Gradient(ref gradient) => {
|
||||
webrender_traits::BorderDetails::Gradient(webrender_traits::GradientBorder {
|
||||
gradient: builder.create_gradient(
|
||||
gradient.gradient.start_point.to_pointf(),
|
||||
gradient.gradient.end_point.to_pointf(),
|
||||
gradient.gradient.stops.clone(),
|
||||
ExtendMode::Clamp),
|
||||
outset: gradient.outset,
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
builder.push_border(rect, clip, widths, details);
|
||||
}
|
||||
DisplayItem::Gradient(ref item) => {
|
||||
let rect = item.base.bounds.to_rectf();
|
||||
let start_point = item.start_point.to_pointf();
|
||||
let end_point = item.end_point.to_pointf();
|
||||
let start_point = item.gradient.start_point.to_pointf();
|
||||
let end_point = item.gradient.end_point.to_pointf();
|
||||
let clip = item.base.clip.to_clip_region(builder);
|
||||
builder.push_gradient(rect,
|
||||
clip,
|
||||
start_point,
|
||||
end_point,
|
||||
item.stops.clone(),
|
||||
item.gradient.stops.clone(),
|
||||
ExtendMode::Clamp);
|
||||
}
|
||||
DisplayItem::Line(..) => {
|
||||
|
@ -394,10 +404,6 @@ impl WebRenderDisplayItemConverter for DisplayItem {
|
|||
let stacking_context = &item.stacking_context;
|
||||
debug_assert!(stacking_context.context_type == StackingContextType::Real);
|
||||
|
||||
let clip = builder.new_clip_region(&stacking_context.overflow.to_rectf(),
|
||||
vec![],
|
||||
None);
|
||||
|
||||
let transform = stacking_context.transform.map(|transform| {
|
||||
LayoutTransform::from_untyped(&transform).into()
|
||||
});
|
||||
|
@ -407,7 +413,6 @@ impl WebRenderDisplayItemConverter for DisplayItem {
|
|||
|
||||
builder.push_stacking_context(stacking_context.scroll_policy,
|
||||
stacking_context.bounds.to_rectf(),
|
||||
clip,
|
||||
stacking_context.z_index,
|
||||
transform,
|
||||
perspective,
|
||||
|
|
|
@ -120,7 +120,7 @@ use style::stylesheets::{Origin, Stylesheet, UserAgentStylesheets};
|
|||
use style::stylist::Stylist;
|
||||
use style::thread_state;
|
||||
use style::timer::Timer;
|
||||
use style::traversal::{DomTraversal, TraversalDriver};
|
||||
use style::traversal::{DomTraversal, TraversalDriver, TraversalFlags};
|
||||
|
||||
/// Information needed by the layout thread.
|
||||
pub struct LayoutThread {
|
||||
|
@ -520,6 +520,7 @@ impl LayoutThread {
|
|||
local_context_creation_data: Mutex::new(thread_local_style_context_creation_data),
|
||||
timer: self.timer.clone(),
|
||||
quirks_mode: self.quirks_mode.unwrap(),
|
||||
animation_only_restyle: false,
|
||||
},
|
||||
image_cache_thread: Mutex::new(self.image_cache_thread.clone()),
|
||||
font_cache_thread: Mutex::new(self.font_cache_thread.clone()),
|
||||
|
@ -1143,7 +1144,7 @@ impl LayoutThread {
|
|||
let stylist = &<RecalcStyleAndConstructFlows as
|
||||
DomTraversal<ServoLayoutElement>>::shared_context(&traversal).stylist;
|
||||
<RecalcStyleAndConstructFlows as
|
||||
DomTraversal<ServoLayoutElement>>::pre_traverse(element, stylist, /* skip_root = */ false)
|
||||
DomTraversal<ServoLayoutElement>>::pre_traverse(element, stylist, TraversalFlags::empty())
|
||||
};
|
||||
|
||||
if token.should_traverse() {
|
||||
|
|
|
@ -10,6 +10,7 @@ name = "net"
|
|||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.4.1"
|
||||
brotli = "1.0.6"
|
||||
cookie = "0.2.5"
|
||||
devtools_traits = {path = "../devtools_traits"}
|
||||
|
@ -27,7 +28,6 @@ net_traits = {path = "../net_traits"}
|
|||
openssl = "0.7.6"
|
||||
openssl-verify = "0.1"
|
||||
profile_traits = {path = "../profile_traits"}
|
||||
rustc-serialize = "0.3"
|
||||
serde = "0.9"
|
||||
serde_derive = "0.9"
|
||||
serde_json = "0.9"
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* 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/. */
|
||||
|
||||
use base64;
|
||||
use hyper::mime::{Attr, Mime, SubLevel, TopLevel, Value};
|
||||
use rustc_serialize::base64::FromBase64;
|
||||
use servo_url::ServoUrl;
|
||||
use url::Position;
|
||||
use url::percent_encoding::percent_decode;
|
||||
|
@ -46,7 +46,7 @@ pub fn decode(url: &ServoUrl) -> Result<DecodeData, DecodeError> {
|
|||
// FIXME(#2909): It’s unclear what to do with non-alphabet characters,
|
||||
// but Acid 3 apparently depends on spaces being ignored.
|
||||
bytes = bytes.into_iter().filter(|&b| b != b' ').collect::<Vec<u8>>();
|
||||
match bytes.from_base64() {
|
||||
match base64::decode(&bytes) {
|
||||
Err(..) => return Err(DecodeError::NonBase64DataUri),
|
||||
Ok(data) => bytes = data,
|
||||
}
|
||||
|
|
|
@ -192,7 +192,7 @@ pub fn main_fetch(request: Rc<Request>,
|
|||
.read()
|
||||
.unwrap()
|
||||
.is_host_secure(request.current_url().domain().unwrap()) {
|
||||
request.url_list.borrow_mut().last_mut().unwrap().as_mut_url().unwrap().set_scheme("https").unwrap();
|
||||
request.url_list.borrow_mut().last_mut().unwrap().as_mut_url().set_scheme("https").unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ use hsts::HstsList;
|
|||
use hyper::Error as HttpError;
|
||||
use hyper::LanguageTag;
|
||||
use hyper::client::{Pool, Request as HyperRequest, Response as HyperResponse};
|
||||
use hyper::client::pool::PooledStream;
|
||||
use hyper::header::{AcceptEncoding, AcceptLanguage, AccessControlAllowCredentials};
|
||||
use hyper::header::{AccessControlAllowOrigin, AccessControlAllowHeaders, AccessControlAllowMethods};
|
||||
use hyper::header::{AccessControlRequestHeaders, AccessControlMaxAge, AccessControlRequestMethod};
|
||||
|
@ -24,17 +25,18 @@ use hyper::header::{IfUnmodifiedSince, IfModifiedSince, IfNoneMatch, Location, P
|
|||
use hyper::header::{QualityItem, Referer, SetCookie, UserAgent, qitem};
|
||||
use hyper::header::Origin as HyperOrigin;
|
||||
use hyper::method::Method;
|
||||
use hyper::net::Fresh;
|
||||
use hyper::net::{Fresh, HttpStream, HttpsStream, NetworkConnector};
|
||||
use hyper::status::StatusCode;
|
||||
use hyper_serde::Serde;
|
||||
use log;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use net_traits::{CookieSource, FetchMetadata, NetworkError, ReferrerPolicy};
|
||||
use net_traits::hosts::replace_hosts;
|
||||
use net_traits::hosts::replace_host;
|
||||
use net_traits::request::{CacheMode, CredentialsMode, Destination, Origin};
|
||||
use net_traits::request::{RedirectMode, Referrer, Request, RequestMode, ResponseTainting};
|
||||
use net_traits::response::{HttpsState, Response, ResponseBody, ResponseType};
|
||||
use openssl;
|
||||
use openssl::ssl::SslStream;
|
||||
use openssl::ssl::error::{OpensslError, SslError};
|
||||
use resource_thread::AuthCache;
|
||||
use servo_url::{ImmutableOrigin, ServoUrl};
|
||||
|
@ -125,12 +127,18 @@ struct NetworkHttpRequestFactory {
|
|||
pub connector: Arc<Pool<Connector>>,
|
||||
}
|
||||
|
||||
impl NetworkConnector for NetworkHttpRequestFactory {
|
||||
type Stream = PooledStream<HttpsStream<SslStream<HttpStream>>>;
|
||||
|
||||
fn connect(&self, host: &str, port: u16, scheme: &str) -> Result<Self::Stream, HttpError> {
|
||||
self.connector.connect(&replace_host(host), port, scheme)
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkHttpRequestFactory {
|
||||
fn create(&self, url: ServoUrl, method: Method, headers: Headers)
|
||||
-> Result<HyperRequest<Fresh>, NetworkError> {
|
||||
let connection = HyperRequest::with_connector(method,
|
||||
url.clone().into_url().unwrap(),
|
||||
&*self.connector);
|
||||
let connection = HyperRequest::with_connector(method, url.clone().into_url(), self);
|
||||
|
||||
if let Err(HttpError::Ssl(ref error)) = connection {
|
||||
let error: &(Error + Send + 'static) = &**error;
|
||||
|
@ -222,7 +230,7 @@ fn strict_origin_when_cross_origin(referrer_url: ServoUrl, url: ServoUrl) -> Opt
|
|||
fn strip_url(mut referrer_url: ServoUrl, origin_only: bool) -> Option<ServoUrl> {
|
||||
if referrer_url.scheme() == "https" || referrer_url.scheme() == "http" {
|
||||
{
|
||||
let referrer = referrer_url.as_mut_url().unwrap();
|
||||
let referrer = referrer_url.as_mut_url();
|
||||
referrer.set_username("").unwrap();
|
||||
referrer.set_password(None).unwrap();
|
||||
referrer.set_fragment(None);
|
||||
|
@ -408,7 +416,6 @@ fn obtain_response(request_factory: &NetworkHttpRequestFactory,
|
|||
is_xhr: bool)
|
||||
-> Result<(WrappedHttpResponse, Option<ChromeToDevtoolsControlMsg>), NetworkError> {
|
||||
let null_data = None;
|
||||
let connection_url = replace_hosts(&url);
|
||||
|
||||
// loop trying connections in connection pool
|
||||
// they may have grown stale (disconnected), in which case we'll get
|
||||
|
@ -439,7 +446,7 @@ fn obtain_response(request_factory: &NetworkHttpRequestFactory,
|
|||
}
|
||||
|
||||
if log_enabled!(log::LogLevel::Info) {
|
||||
info!("{} {}", method, connection_url);
|
||||
info!("{} {}", method, url);
|
||||
for header in headers.iter() {
|
||||
info!(" - {}", header);
|
||||
}
|
||||
|
@ -448,7 +455,7 @@ fn obtain_response(request_factory: &NetworkHttpRequestFactory,
|
|||
|
||||
let connect_start = precise_time_ms();
|
||||
|
||||
let request = try!(request_factory.create(connection_url.clone(), method.clone(),
|
||||
let request = try!(request_factory.create(url.clone(), method.clone(),
|
||||
headers.clone()));
|
||||
|
||||
let connect_end = precise_time_ms();
|
||||
|
@ -900,7 +907,7 @@ fn http_network_or_cache_fetch(request: Rc<Request>,
|
|||
let headers = &mut *http_request.headers.borrow_mut();
|
||||
let host = Host {
|
||||
hostname: current_url.host_str().unwrap().to_owned(),
|
||||
port: current_url.port_or_known_default()
|
||||
port: current_url.port()
|
||||
};
|
||||
headers.set(host);
|
||||
// unlike http_loader, we should not set the accept header
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#![feature(mpsc_select)]
|
||||
#![feature(step_by)]
|
||||
|
||||
extern crate base64;
|
||||
extern crate brotli;
|
||||
extern crate cookie as cookie_rs;
|
||||
extern crate devtools_traits;
|
||||
|
@ -25,7 +26,6 @@ extern crate net_traits;
|
|||
extern crate openssl;
|
||||
extern crate openssl_verify;
|
||||
extern crate profile_traits;
|
||||
extern crate rustc_serialize;
|
||||
extern crate serde;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
* 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/. */
|
||||
|
||||
use base64;
|
||||
use net_traits::response::{Response, ResponseBody, ResponseType};
|
||||
use openssl::crypto::hash::{hash, Type as MessageDigest};
|
||||
use rustc_serialize::base64::{STANDARD, ToBase64};
|
||||
use std::iter::Filter;
|
||||
use std::str::Split;
|
||||
use std::sync::MutexGuard;
|
||||
|
@ -120,7 +120,7 @@ fn apply_algorithm_to_response(body: MutexGuard<ResponseBody>,
|
|||
-> String {
|
||||
if let ResponseBody::Done(ref vec) = *body {
|
||||
let response_digest = hash(message_digest, vec);
|
||||
response_digest.to_base64(STANDARD)
|
||||
base64::encode(&response_digest)
|
||||
} else {
|
||||
unreachable!("Tried to calculate digest of incomplete response body")
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use http_loader;
|
|||
use hyper::header::{Host, SetCookie};
|
||||
use net_traits::{CookieSource, MessageData, WebSocketCommunicate};
|
||||
use net_traits::{WebSocketConnectData, WebSocketDomAction, WebSocketNetworkEvent};
|
||||
use net_traits::hosts::replace_hosts;
|
||||
use net_traits::hosts::replace_host_in_url;
|
||||
use servo_url::ServoUrl;
|
||||
use std::ascii::AsciiExt;
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
|
@ -25,84 +25,6 @@ use websocket::stream::WebSocketStream;
|
|||
use websocket::ws::receiver::Receiver as WSReceiver;
|
||||
use websocket::ws::sender::Sender as Sender_Object;
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-websocket-establish
|
||||
fn establish_a_websocket_connection(resource_url: &ServoUrl,
|
||||
origin: String,
|
||||
protocols: Vec<String>,
|
||||
cookie_jar: Arc<RwLock<CookieStorage>>)
|
||||
-> WebSocketResult<(Option<String>,
|
||||
Sender<WebSocketStream>,
|
||||
Receiver<WebSocketStream>)> {
|
||||
// Steps 1-2 are not really applicable here, given we don't exactly go
|
||||
// through the same infrastructure as the Fetch spec.
|
||||
|
||||
if should_be_blocked_due_to_bad_port(resource_url) {
|
||||
// Subset of steps 11-12, we inline the bad port check here from the
|
||||
// main fetch algorithm for the same reason steps 1-2 are not
|
||||
// applicable.
|
||||
return Err(WebSocketError::RequestError("Request should be blocked due to bad port."));
|
||||
}
|
||||
|
||||
// Steps 3-7.
|
||||
let net_url = replace_hosts(resource_url);
|
||||
let mut request = try!(Client::connect(net_url.as_url()));
|
||||
|
||||
// Client::connect sets the Host header to the host of the URL that is
|
||||
// passed to it, so we need to reset it afterwards to the correct one.
|
||||
request.headers.set(Host {
|
||||
hostname: resource_url.host_str().unwrap().to_owned(),
|
||||
port: resource_url.port(),
|
||||
});
|
||||
|
||||
// Step 8.
|
||||
if !protocols.is_empty() {
|
||||
request.headers.set(WebSocketProtocol(protocols.clone()));
|
||||
}
|
||||
|
||||
// Steps 9-10.
|
||||
// TODO: support for permessage-deflate extension.
|
||||
|
||||
// Subset of step 11.
|
||||
// See step 2 of https://fetch.spec.whatwg.org/#concept-fetch.
|
||||
request.headers.set(Origin(origin));
|
||||
|
||||
// Transitive subset of step 11.
|
||||
// See step 17.1 of https://fetch.spec.whatwg.org/#concept-http-network-or-cache-fetch.
|
||||
http_loader::set_request_cookies(&resource_url, &mut request.headers, &cookie_jar);
|
||||
|
||||
// Step 11, somewhat.
|
||||
let response = try!(request.send());
|
||||
|
||||
// Step 12, 14.
|
||||
try!(response.validate());
|
||||
|
||||
// Step 13 and transitive subset of step 14.
|
||||
// See step 6 of http://tools.ietf.org/html/rfc6455#section-4.1.
|
||||
let protocol_in_use = response.protocol().and_then(|header| {
|
||||
// https://github.com/whatwg/fetch/issues/515
|
||||
header.first().cloned()
|
||||
});
|
||||
if let Some(ref protocol_name) = protocol_in_use {
|
||||
if !protocols.is_empty() && !protocols.iter().any(|p| (&**p).eq_ignore_ascii_case(protocol_name)) {
|
||||
return Err(WebSocketError::ProtocolError("Protocol in Use not in client-supplied protocol list"));
|
||||
};
|
||||
};
|
||||
|
||||
// Transitive subset of step 11.
|
||||
// See step 15 of https://fetch.spec.whatwg.org/#http-network-fetch.
|
||||
if let Some(cookies) = response.headers.get::<SetCookie>() {
|
||||
let mut jar = cookie_jar.write().unwrap();
|
||||
for cookie in &**cookies {
|
||||
if let Some(cookie) = Cookie::new_wrapped(cookie.clone(), resource_url, CookieSource::HTTP) {
|
||||
jar.push(cookie, resource_url, CookieSource::HTTP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let (sender, receiver) = response.begin().split();
|
||||
Ok((protocol_in_use, sender, receiver))
|
||||
}
|
||||
|
||||
pub fn init(connect: WebSocketCommunicate, connect_data: WebSocketConnectData, cookie_jar: Arc<RwLock<CookieStorage>>) {
|
||||
thread::Builder::new().name(format!("WebSocket connection to {}", connect_data.resource_url)).spawn(move || {
|
||||
let channel = establish_a_websocket_connection(&connect_data.resource_url,
|
||||
|
@ -182,3 +104,81 @@ pub fn init(connect: WebSocketCommunicate, connect_data: WebSocketConnectData, c
|
|||
}
|
||||
}).expect("Thread spawning failed");
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-websocket-establish
|
||||
fn establish_a_websocket_connection(resource_url: &ServoUrl,
|
||||
origin: String,
|
||||
protocols: Vec<String>,
|
||||
cookie_jar: Arc<RwLock<CookieStorage>>)
|
||||
-> WebSocketResult<(Option<String>,
|
||||
Sender<WebSocketStream>,
|
||||
Receiver<WebSocketStream>)> {
|
||||
// Steps 1-2 are not really applicable here, given we don't exactly go
|
||||
// through the same infrastructure as the Fetch spec.
|
||||
|
||||
if should_be_blocked_due_to_bad_port(resource_url) {
|
||||
// Subset of steps 11-12, we inline the bad port check here from the
|
||||
// main fetch algorithm for the same reason steps 1-2 are not
|
||||
// applicable.
|
||||
return Err(WebSocketError::RequestError("Request should be blocked due to bad port."));
|
||||
}
|
||||
|
||||
// Steps 3-7.
|
||||
let net_url = replace_host_in_url(resource_url.clone());
|
||||
let mut request = try!(Client::connect(net_url.as_url()));
|
||||
|
||||
// Client::connect sets the Host header to the host of the URL that is
|
||||
// passed to it, so we need to reset it afterwards to the correct one.
|
||||
request.headers.set(Host {
|
||||
hostname: resource_url.host_str().unwrap().to_owned(),
|
||||
port: resource_url.port(),
|
||||
});
|
||||
|
||||
// Step 8.
|
||||
if !protocols.is_empty() {
|
||||
request.headers.set(WebSocketProtocol(protocols.clone()));
|
||||
}
|
||||
|
||||
// Steps 9-10.
|
||||
// TODO: support for permessage-deflate extension.
|
||||
|
||||
// Subset of step 11.
|
||||
// See step 2 of https://fetch.spec.whatwg.org/#concept-fetch.
|
||||
request.headers.set(Origin(origin));
|
||||
|
||||
// Transitive subset of step 11.
|
||||
// See step 17.1 of https://fetch.spec.whatwg.org/#concept-http-network-or-cache-fetch.
|
||||
http_loader::set_request_cookies(&resource_url, &mut request.headers, &cookie_jar);
|
||||
|
||||
// Step 11, somewhat.
|
||||
let response = try!(request.send());
|
||||
|
||||
// Step 12, 14.
|
||||
try!(response.validate());
|
||||
|
||||
// Step 13 and transitive subset of step 14.
|
||||
// See step 6 of http://tools.ietf.org/html/rfc6455#section-4.1.
|
||||
let protocol_in_use = response.protocol().and_then(|header| {
|
||||
// https://github.com/whatwg/fetch/issues/515
|
||||
header.first().cloned()
|
||||
});
|
||||
if let Some(ref protocol_name) = protocol_in_use {
|
||||
if !protocols.is_empty() && !protocols.iter().any(|p| (&**p).eq_ignore_ascii_case(protocol_name)) {
|
||||
return Err(WebSocketError::ProtocolError("Protocol in Use not in client-supplied protocol list"));
|
||||
};
|
||||
};
|
||||
|
||||
// Transitive subset of step 11.
|
||||
// See step 15 of https://fetch.spec.whatwg.org/#http-network-fetch.
|
||||
if let Some(cookies) = response.headers.get::<SetCookie>() {
|
||||
let mut jar = cookie_jar.write().unwrap();
|
||||
for cookie in &**cookies {
|
||||
if let Some(cookie) = Cookie::new_wrapped(cookie.clone(), resource_url, CookieSource::HTTP) {
|
||||
jar.push(cookie, resource_url, CookieSource::HTTP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let (sender, receiver) = response.begin().split();
|
||||
Ok((protocol_in_use, sender, receiver))
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
use parse_hosts::HostsFile;
|
||||
use servo_url::ServoUrl;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
|
@ -56,19 +57,24 @@ pub fn parse_hostsfile(hostsfile_content: &str) -> HashMap<String, IpAddr> {
|
|||
host_table
|
||||
}
|
||||
|
||||
pub fn replace_hosts(url: &ServoUrl) -> ServoUrl {
|
||||
HOST_TABLE.lock().unwrap().as_ref().map_or_else(|| url.clone(),
|
||||
|host_table| host_replacement(host_table, url))
|
||||
pub fn replace_host(host: &str) -> Cow<str> {
|
||||
HOST_TABLE.lock().unwrap().as_ref()
|
||||
.and_then(|table| table.get(host))
|
||||
.map_or(host.into(), |replaced_host| replaced_host.to_string().into())
|
||||
}
|
||||
|
||||
pub fn host_replacement(host_table: &HashMap<String, IpAddr>, url: &ServoUrl) -> ServoUrl {
|
||||
url.domain()
|
||||
.and_then(|domain| {
|
||||
host_table.get(domain).map(|ip| {
|
||||
let mut new_url = url.clone();
|
||||
new_url.set_ip_host(*ip).unwrap();
|
||||
new_url
|
||||
})
|
||||
})
|
||||
.unwrap_or_else(|| url.clone())
|
||||
pub fn replace_host_in_url(url: ServoUrl) -> ServoUrl {
|
||||
if let Some(table) = HOST_TABLE.lock().unwrap().as_ref() {
|
||||
host_replacement(table, url)
|
||||
} else {
|
||||
url
|
||||
}
|
||||
}
|
||||
|
||||
pub fn host_replacement(host_table: &HashMap<String, IpAddr>, mut url: ServoUrl) -> ServoUrl {
|
||||
let replacement = url.domain().and_then(|domain| host_table.get(domain));
|
||||
if let Some(ip) = replacement {
|
||||
url.set_ip_host(*ip).unwrap();
|
||||
}
|
||||
url
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ angle = {git = "https://github.com/servo/angle", branch = "servo"}
|
|||
app_units = "0.4"
|
||||
audio-video-metadata = "0.1.2"
|
||||
atomic_refcell = "0.1"
|
||||
base64 = "0.4.1"
|
||||
bitflags = "0.7"
|
||||
bluetooth_traits = {path = "../bluetooth_traits"}
|
||||
byteorder = "1.0"
|
||||
|
@ -69,7 +70,6 @@ range = {path = "../range"}
|
|||
ref_filter_map = "1.0.1"
|
||||
ref_slice = "1.0"
|
||||
regex = "0.2"
|
||||
rustc-serialize = "0.3"
|
||||
script_layout_interface = {path = "../script_layout_interface"}
|
||||
script_plugins = {path = "../script_plugins"}
|
||||
script_traits = {path = "../script_traits"}
|
||||
|
|
|
@ -180,9 +180,9 @@ pub enum AdjacentPosition {
|
|||
}
|
||||
|
||||
impl<'a> TryFrom<&'a str> for AdjacentPosition {
|
||||
type Err = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(position: &'a str) -> Result<AdjacentPosition, Self::Err> {
|
||||
fn try_from(position: &'a str) -> Result<AdjacentPosition, Self::Error> {
|
||||
match_ignore_ascii_case! { &*position,
|
||||
"beforebegin" => Ok(AdjacentPosition::BeforeBegin),
|
||||
"afterbegin" => Ok(AdjacentPosition::AfterBegin),
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
use base64;
|
||||
use dom::bindings::cell::DOMRefCell;
|
||||
use dom::bindings::codegen::Bindings::BlobBinding::BlobMethods;
|
||||
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
|
||||
|
@ -29,7 +30,6 @@ use js::jsapi::JSAutoCompartment;
|
|||
use js::jsapi::JSContext;
|
||||
use js::jsval::{self, JSVal};
|
||||
use js::typedarray::{ArrayBuffer, CreateWith};
|
||||
use rustc_serialize::base64::{CharacterSet, Config, Newline, ToBase64};
|
||||
use script_thread::RunnableWrapper;
|
||||
use servo_atoms::Atom;
|
||||
use std::cell::Cell;
|
||||
|
@ -247,13 +247,7 @@ impl FileReader {
|
|||
|
||||
//https://w3c.github.io/FileAPI/#dfn-readAsDataURL
|
||||
fn perform_readasdataurl(result: &DOMRefCell<Option<FileReaderResult>>, data: ReadMetaData, bytes: &[u8]) {
|
||||
let config = Config {
|
||||
char_set: CharacterSet::UrlSafe,
|
||||
newline: Newline::LF,
|
||||
pad: true,
|
||||
line_length: None
|
||||
};
|
||||
let base64 = bytes.to_base64(config);
|
||||
let base64 = base64::encode(bytes);
|
||||
|
||||
let output = if data.blobtype.is_empty() {
|
||||
format!("data:base64,{}", base64)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
use base64;
|
||||
use canvas_traits::{CanvasMsg, FromScriptMsg};
|
||||
use dom::attr::Attr;
|
||||
use dom::bindings::cell::DOMRefCell;
|
||||
|
@ -33,7 +34,6 @@ use ipc_channel::ipc::{self, IpcSender};
|
|||
use js::error::throw_type_error;
|
||||
use js::jsapi::{HandleValue, JSContext};
|
||||
use offscreen_gl_context::GLContextAttributes;
|
||||
use rustc_serialize::base64::{STANDARD, ToBase64};
|
||||
use script_layout_interface::HTMLCanvasData;
|
||||
use std::iter::repeat;
|
||||
use style::attr::AttrValue;
|
||||
|
@ -296,7 +296,7 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement {
|
|||
encoder.encode(&raw_data, self.Width(), self.Height(), ColorType::RGBA(8)).unwrap();
|
||||
}
|
||||
|
||||
let encoded = encoded.to_base64(STANDARD);
|
||||
let encoded = base64::encode(&encoded);
|
||||
Ok(DOMString::from(format!("data:{};base64,{}", mime_type, encoded)))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -384,12 +384,12 @@ impl HTMLFormElement {
|
|||
fn mutate_action_url(&self, form_data: &mut Vec<FormDatum>, mut load_data: LoadData, encoding: EncodingRef) {
|
||||
let charset = &*encoding.whatwg_name().unwrap();
|
||||
|
||||
if let Some(ref mut url) = load_data.url.as_mut_url() {
|
||||
url.query_pairs_mut().clear()
|
||||
.encoding_override(Some(self.pick_encoding()))
|
||||
.extend_pairs(form_data.into_iter()
|
||||
.map(|field| (field.name.clone(), field.replace_value(charset))));
|
||||
}
|
||||
load_data.url
|
||||
.as_mut_url()
|
||||
.query_pairs_mut().clear()
|
||||
.encoding_override(Some(self.pick_encoding()))
|
||||
.extend_pairs(form_data.into_iter()
|
||||
.map(|field| (field.name.clone(), field.replace_value(charset))));
|
||||
|
||||
self.plan_to_navigate(load_data);
|
||||
}
|
||||
|
@ -403,13 +403,12 @@ impl HTMLFormElement {
|
|||
let charset = &*encoding.whatwg_name().unwrap();
|
||||
load_data.headers.set(ContentType::form_url_encoded());
|
||||
|
||||
|
||||
if let Some(ref mut url) = load_data.url.as_mut_url() {
|
||||
url.query_pairs_mut().clear()
|
||||
.encoding_override(Some(self.pick_encoding()))
|
||||
.extend_pairs(form_data.into_iter()
|
||||
.map(|field| (field.name.clone(), field.replace_value(charset))));
|
||||
}
|
||||
load_data.url
|
||||
.as_mut_url()
|
||||
.query_pairs_mut().clear()
|
||||
.encoding_override(Some(self.pick_encoding()))
|
||||
.extend_pairs(form_data.into_iter()
|
||||
.map(|field| (field.name.clone(), field.replace_value(charset))));
|
||||
|
||||
load_data.url.query().unwrap_or("").to_string().into_bytes()
|
||||
}
|
||||
|
|
|
@ -52,9 +52,8 @@ impl URL {
|
|||
}
|
||||
|
||||
pub fn set_query_pairs(&self, pairs: &[(String, String)]) {
|
||||
if let Some(ref mut url) = self.url.borrow_mut().as_mut_url() {
|
||||
url.query_pairs_mut().clear().extend_pairs(pairs);
|
||||
}
|
||||
let mut url = self.url.borrow_mut();
|
||||
url.as_mut_url().query_pairs_mut().clear().extend_pairs(pairs);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,49 +45,31 @@ impl UrlHelper {
|
|||
USVString(quirks::username(url.as_url()).to_owned())
|
||||
}
|
||||
pub fn SetHash(url: &mut ServoUrl, value: USVString) {
|
||||
if let Some(ref mut url) = url.as_mut_url() {
|
||||
quirks::set_hash(url, &value.0)
|
||||
}
|
||||
quirks::set_hash(url.as_mut_url(), &value.0)
|
||||
}
|
||||
pub fn SetHost(url: &mut ServoUrl, value: USVString) {
|
||||
if let Some(ref mut url) = url.as_mut_url() {
|
||||
let _ = quirks::set_host(url, &value.0);
|
||||
}
|
||||
let _ = quirks::set_host(url.as_mut_url(), &value.0);
|
||||
}
|
||||
pub fn SetPort(url: &mut ServoUrl, value: USVString) {
|
||||
if let Some(ref mut url) = url.as_mut_url() {
|
||||
let _ = quirks::set_port(url, &value.0);
|
||||
}
|
||||
let _ = quirks::set_port(url.as_mut_url(), &value.0);
|
||||
}
|
||||
pub fn SetSearch(url: &mut ServoUrl, value: USVString) {
|
||||
if let Some(ref mut url) = url.as_mut_url() {
|
||||
quirks::set_search(url, &value.0)
|
||||
}
|
||||
quirks::set_search(url.as_mut_url(), &value.0)
|
||||
}
|
||||
pub fn SetPathname(url: &mut ServoUrl, value: USVString) {
|
||||
if let Some(ref mut url) = url.as_mut_url() {
|
||||
quirks::set_pathname(url, &value.0)
|
||||
}
|
||||
quirks::set_pathname(url.as_mut_url(), &value.0)
|
||||
}
|
||||
pub fn SetHostname(url: &mut ServoUrl, value: USVString) {
|
||||
if let Some(ref mut url) = url.as_mut_url() {
|
||||
let _ = quirks::set_hostname(url, &value.0);
|
||||
}
|
||||
let _ = quirks::set_hostname(url.as_mut_url(), &value.0);
|
||||
}
|
||||
pub fn SetPassword(url: &mut ServoUrl, value: USVString) {
|
||||
if let Some(ref mut url) = url.as_mut_url() {
|
||||
let _ = quirks::set_password(url, &value.0);
|
||||
}
|
||||
let _ = quirks::set_password(url.as_mut_url(), &value.0);
|
||||
}
|
||||
pub fn SetProtocol(url: &mut ServoUrl, value: USVString) {
|
||||
if let Some(ref mut url) = url.as_mut_url() {
|
||||
let _ = quirks::set_protocol(url, &value.0);
|
||||
}
|
||||
let _ = quirks::set_protocol(url.as_mut_url(), &value.0);
|
||||
}
|
||||
pub fn SetUsername(url: &mut ServoUrl, value: USVString) {
|
||||
if let Some(ref mut url) = url.as_mut_url() {
|
||||
let _ = quirks::set_username(url, &value.0);
|
||||
}
|
||||
let _ = quirks::set_username(url.as_mut_url(), &value.0);
|
||||
}
|
||||
// https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy
|
||||
pub fn is_origin_trustworthy(url: &ServoUrl) -> bool {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use app_units::Au;
|
||||
use base64;
|
||||
use bluetooth_traits::BluetoothRequest;
|
||||
use cssparser::Parser;
|
||||
use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType};
|
||||
|
@ -68,7 +69,6 @@ use num_traits::ToPrimitive;
|
|||
use open;
|
||||
use profile_traits::mem::ProfilerChan as MemProfilerChan;
|
||||
use profile_traits::time::ProfilerChan as TimeProfilerChan;
|
||||
use rustc_serialize::base64::{FromBase64, STANDARD, ToBase64};
|
||||
use script_layout_interface::{TrustedNodeAddress, PendingImageState};
|
||||
use script_layout_interface::message::{Msg, Reflow, ReflowQueryType, ScriptReflow};
|
||||
use script_layout_interface::reporter::CSSErrorReporter;
|
||||
|
@ -410,16 +410,13 @@ pub fn base64_btoa(input: DOMString) -> Fallible<DOMString> {
|
|||
|
||||
// "and then must apply the base64 algorithm to that sequence of
|
||||
// octets, and return the result. [RFC4648]"
|
||||
Ok(DOMString::from(octets.to_base64(STANDARD)))
|
||||
Ok(DOMString::from(base64::encode(&octets)))
|
||||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#atob
|
||||
pub fn base64_atob(input: DOMString) -> Fallible<DOMString> {
|
||||
// "Remove all space characters from input."
|
||||
// serialize::base64::from_base64 ignores \r and \n,
|
||||
// but it treats the other space characters as
|
||||
// invalid input.
|
||||
fn is_html_space(c: char) -> bool {
|
||||
HTML_SPACE_CHARACTERS.iter().any(|&m| m == c)
|
||||
}
|
||||
|
@ -456,7 +453,7 @@ pub fn base64_atob(input: DOMString) -> Fallible<DOMString> {
|
|||
return Err(Error::InvalidCharacter)
|
||||
}
|
||||
|
||||
match input.from_base64() {
|
||||
match base64::decode(&input) {
|
||||
Ok(data) => Ok(DOMString::from(data.iter().map(|&b| b as char).collect::<String>())),
|
||||
Err(..) => Err(Error::InvalidCharacter)
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ extern crate angle;
|
|||
extern crate app_units;
|
||||
extern crate atomic_refcell;
|
||||
extern crate audio_video_metadata;
|
||||
extern crate base64;
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
extern crate bluetooth_traits;
|
||||
|
@ -78,7 +79,6 @@ extern crate range;
|
|||
extern crate ref_filter_map;
|
||||
extern crate ref_slice;
|
||||
extern crate regex;
|
||||
extern crate rustc_serialize;
|
||||
extern crate script_layout_interface;
|
||||
extern crate script_traits;
|
||||
extern crate selectors;
|
||||
|
|
|
@ -87,6 +87,9 @@ pub struct SharedStyleContext<'a> {
|
|||
|
||||
/// The QuirksMode state which the document needs to be rendered with
|
||||
pub quirks_mode: QuirksMode,
|
||||
|
||||
/// True if the traversal is processing only animation restyles.
|
||||
pub animation_only_restyle: bool,
|
||||
}
|
||||
|
||||
impl<'a> SharedStyleContext<'a> {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
use dom::TElement;
|
||||
use properties::ComputedValues;
|
||||
use properties::longhands::display::computed_value as display;
|
||||
use restyle_hints::{RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint};
|
||||
use restyle_hints::{RESTYLE_CSS_ANIMATIONS, RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint};
|
||||
use rule_tree::StrongRuleNode;
|
||||
use selector_parser::{PseudoElement, RestyleDamage, Snapshot};
|
||||
use std::collections::HashMap;
|
||||
|
@ -136,7 +136,12 @@ pub struct StoredRestyleHint(RestyleHint);
|
|||
impl StoredRestyleHint {
|
||||
/// Propagates this restyle hint to a child element.
|
||||
pub fn propagate(&self) -> Self {
|
||||
StoredRestyleHint(if self.0.contains(RESTYLE_DESCENDANTS) {
|
||||
// If we have RESTYLE_CSS_ANIMATIONS restyle hint, it means we are in the
|
||||
// middle of an animation only restyle. In that case, we don't need to
|
||||
// propagate any restyle hints.
|
||||
StoredRestyleHint(if self.0.contains(RESTYLE_CSS_ANIMATIONS) {
|
||||
RestyleHint::empty()
|
||||
} else if self.0.contains(RESTYLE_DESCENDANTS) {
|
||||
RESTYLE_SELF | RESTYLE_DESCENDANTS
|
||||
} else {
|
||||
RestyleHint::empty()
|
||||
|
@ -174,6 +179,16 @@ impl StoredRestyleHint {
|
|||
pub fn insert(&mut self, other: &Self) {
|
||||
self.0 |= other.0
|
||||
}
|
||||
|
||||
/// Remove animation restyle hint.
|
||||
pub fn remove_animation_hint(&mut self) {
|
||||
self.0.remove(RESTYLE_CSS_ANIMATIONS)
|
||||
}
|
||||
|
||||
/// Returns true if the hint has animation-only restyle.
|
||||
pub fn has_animation_hint(&self) -> bool {
|
||||
self.0.contains(RESTYLE_CSS_ANIMATIONS)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for StoredRestyleHint {
|
||||
|
|
|
@ -309,6 +309,24 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
|
|||
/// Only safe to call with exclusive access to the element.
|
||||
unsafe fn unset_dirty_descendants(&self);
|
||||
|
||||
/// Similar to the dirty_descendants but for representing a descendant of
|
||||
/// the element needs to be updated in animation-only traversal.
|
||||
fn has_animation_only_dirty_descendants(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Flag that this element has a descendant for animation-only restyle processing.
|
||||
///
|
||||
/// Only safe to call with exclusive access to the element.
|
||||
unsafe fn set_animation_only_dirty_descendants(&self) {
|
||||
}
|
||||
|
||||
/// Flag that this element has no descendant for animation-only restyle processing.
|
||||
///
|
||||
/// Only safe to call with exclusive access to the element.
|
||||
unsafe fn unset_animation_only_dirty_descendants(&self) {
|
||||
}
|
||||
|
||||
/// Atomically stores the number of children of this node that we will
|
||||
/// need to process during bottom-up traversal.
|
||||
fn store_children_to_process(&self, n: isize);
|
||||
|
@ -354,6 +372,16 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
|
|||
|
||||
/// Returns true if the element has a CSS animation.
|
||||
fn has_css_animations(&self, _pseudo: Option<&PseudoElement>) -> bool;
|
||||
|
||||
/// Returns true if the element has animation restyle hints.
|
||||
fn has_animation_restyle_hints(&self) -> bool {
|
||||
let data = match self.borrow_data() {
|
||||
Some(d) => d,
|
||||
None => return false,
|
||||
};
|
||||
return data.get_restyle()
|
||||
.map_or(false, |r| r.hint.has_animation_hint());
|
||||
}
|
||||
}
|
||||
|
||||
/// TNode and TElement aren't Send because we want to be careful and explicit
|
||||
|
|
|
@ -42,6 +42,7 @@ use gecko_bindings::structs;
|
|||
use gecko_bindings::structs::{RawGeckoElement, RawGeckoNode};
|
||||
use gecko_bindings::structs::{nsIAtom, nsIContent, nsStyleContext};
|
||||
use gecko_bindings::structs::EffectCompositor_CascadeLevel as CascadeLevel;
|
||||
use gecko_bindings::structs::NODE_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO;
|
||||
use gecko_bindings::structs::NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO;
|
||||
use gecko_bindings::structs::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
|
||||
use gecko_bindings::sugar::ownership::HasArcFFI;
|
||||
|
@ -510,6 +511,18 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
self.unset_flags(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32)
|
||||
}
|
||||
|
||||
fn has_animation_only_dirty_descendants(&self) -> bool {
|
||||
self.flags() & (NODE_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32) != 0
|
||||
}
|
||||
|
||||
unsafe fn set_animation_only_dirty_descendants(&self) {
|
||||
self.set_flags(NODE_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32)
|
||||
}
|
||||
|
||||
unsafe fn unset_animation_only_dirty_descendants(&self) {
|
||||
self.unset_flags(NODE_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32)
|
||||
}
|
||||
|
||||
fn store_children_to_process(&self, _: isize) {
|
||||
// This is only used for bottom-up traversal, and is thus a no-op for Gecko.
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1632,14 +1632,14 @@ pub mod root {
|
|||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct MutexImpl {
|
||||
pub platformData_: [*mut ::std::os::raw::c_void; 8usize],
|
||||
pub platformData_: [*mut ::std::os::raw::c_void; 5usize],
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct MutexImpl_PlatformData([u8; 0]);
|
||||
#[test]
|
||||
fn bindgen_test_layout_MutexImpl() {
|
||||
assert_eq!(::std::mem::size_of::<MutexImpl>() , 64usize ,
|
||||
assert_eq!(::std::mem::size_of::<MutexImpl>() , 40usize ,
|
||||
concat ! ( "Size of: " , stringify ! ( MutexImpl )
|
||||
));
|
||||
assert_eq! (::std::mem::align_of::<MutexImpl>() , 8usize ,
|
||||
|
@ -2993,6 +2993,14 @@ pub mod root {
|
|||
#[allow(unused_imports)]
|
||||
use self::super::super::super::super::root;
|
||||
}
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum CSSStyleSheetParsingMode {
|
||||
Author = 0,
|
||||
User = 1,
|
||||
Agent = 2,
|
||||
EndGuard_ = 3,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct OriginAttributesDictionary {
|
||||
|
@ -3052,18 +3060,6 @@ pub mod root {
|
|||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Promise([u8; 0]);
|
||||
pub mod workers {
|
||||
#[allow(unused_imports)]
|
||||
use self::super::super::super::super::root;
|
||||
}
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum CSSStyleSheetParsingMode {
|
||||
Author = 0,
|
||||
User = 1,
|
||||
Agent = 2,
|
||||
EndGuard_ = 3,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct CSSRuleList([u8; 0]);
|
||||
|
@ -4774,92 +4770,6 @@ pub mod root {
|
|||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct EventListenerManager([u8; 0]);
|
||||
/**
|
||||
* BlockingResourceBase
|
||||
* Base class of resources that might block clients trying to acquire them.
|
||||
* Does debugging and deadlock detection in DEBUG builds.
|
||||
**/
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct BlockingResourceBase {
|
||||
pub _address: u8,
|
||||
}
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum BlockingResourceBase_BlockingResourceType {
|
||||
eMutex = 0,
|
||||
eReentrantMonitor = 1,
|
||||
eCondVar = 2,
|
||||
}
|
||||
extern "C" {
|
||||
#[link_name =
|
||||
"_ZN7mozilla20BlockingResourceBase17kResourceTypeNameE"]
|
||||
pub static mut BlockingResourceBase_kResourceTypeName:
|
||||
[*const ::std::os::raw::c_char; 0usize];
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_BlockingResourceBase() {
|
||||
assert_eq!(::std::mem::size_of::<BlockingResourceBase>() , 1usize
|
||||
, concat ! (
|
||||
"Size of: " , stringify ! ( BlockingResourceBase ) ));
|
||||
assert_eq! (::std::mem::align_of::<BlockingResourceBase>() ,
|
||||
1usize , concat ! (
|
||||
"Alignment of " , stringify ! ( BlockingResourceBase )
|
||||
));
|
||||
}
|
||||
/**
|
||||
* OffTheBooksMutex is identical to Mutex, except that OffTheBooksMutex doesn't
|
||||
* include leak checking. Sometimes you want to intentionally "leak" a mutex
|
||||
* until shutdown; in these cases, OffTheBooksMutex is for you.
|
||||
*/
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct OffTheBooksMutex {
|
||||
pub _base: root::mozilla::detail::MutexImpl,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_OffTheBooksMutex() {
|
||||
assert_eq!(::std::mem::size_of::<OffTheBooksMutex>() , 64usize ,
|
||||
concat ! (
|
||||
"Size of: " , stringify ! ( OffTheBooksMutex ) ));
|
||||
assert_eq! (::std::mem::align_of::<OffTheBooksMutex>() , 8usize ,
|
||||
concat ! (
|
||||
"Alignment of " , stringify ! ( OffTheBooksMutex ) ));
|
||||
}
|
||||
/**
|
||||
* Mutex
|
||||
* When possible, use MutexAutoLock/MutexAutoUnlock to lock/unlock this
|
||||
* mutex within a scope, instead of calling Lock/Unlock directly.
|
||||
*/
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct Mutex {
|
||||
pub _base: root::mozilla::OffTheBooksMutex,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_Mutex() {
|
||||
assert_eq!(::std::mem::size_of::<Mutex>() , 64usize , concat ! (
|
||||
"Size of: " , stringify ! ( Mutex ) ));
|
||||
assert_eq! (::std::mem::align_of::<Mutex>() , 8usize , concat ! (
|
||||
"Alignment of " , stringify ! ( Mutex ) ));
|
||||
}
|
||||
pub mod net {
|
||||
#[allow(unused_imports)]
|
||||
use self::super::super::super::root;
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum ReferrerPolicy {
|
||||
RP_No_Referrer = 2,
|
||||
RP_Origin = 3,
|
||||
RP_No_Referrer_When_Downgrade = 1,
|
||||
RP_Origin_When_Crossorigin = 4,
|
||||
RP_Unsafe_URL = 5,
|
||||
RP_Same_Origin = 6,
|
||||
RP_Strict_Origin = 7,
|
||||
RP_Strict_Origin_When_Cross_Origin = 8,
|
||||
RP_Unset = 0,
|
||||
}
|
||||
}
|
||||
pub const FlushType_Frames: root::mozilla::FlushType =
|
||||
FlushType::Style;
|
||||
#[repr(u8)]
|
||||
|
@ -5418,6 +5328,23 @@ pub mod root {
|
|||
assert_eq! (::std::mem::align_of::<StyleSheet>() , 8usize , concat
|
||||
! ( "Alignment of " , stringify ! ( StyleSheet ) ));
|
||||
}
|
||||
pub mod net {
|
||||
#[allow(unused_imports)]
|
||||
use self::super::super::super::root;
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum ReferrerPolicy {
|
||||
RP_No_Referrer = 2,
|
||||
RP_Origin = 3,
|
||||
RP_No_Referrer_When_Downgrade = 1,
|
||||
RP_Origin_When_Crossorigin = 4,
|
||||
RP_Unsafe_URL = 5,
|
||||
RP_Same_Origin = 6,
|
||||
RP_Strict_Origin = 7,
|
||||
RP_Strict_Origin_When_Cross_Origin = 8,
|
||||
RP_Unset = 0,
|
||||
}
|
||||
}
|
||||
#[repr(u8)]
|
||||
/**
|
||||
* Enumeration that represents one of the two supported style system backends.
|
||||
|
@ -5530,7 +5457,7 @@ pub mod root {
|
|||
eUseCounter_ImageBitmapRenderingContext_TransferImageBitmap = 86,
|
||||
eUseCounter_URLCreateObjectURL_MediaStream = 87,
|
||||
eUseCounter_XMLBaseAttribute = 88,
|
||||
eUseCounter_XMLBaseAttributeWithStyledElement = 89,
|
||||
eUseCounter_XMLBaseAttributeForStyleAttr = 89,
|
||||
eUseCounter_Count = 90,
|
||||
}
|
||||
#[repr(u32)]
|
||||
|
@ -6795,6 +6722,75 @@ pub mod root {
|
|||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct RestyleManager([u8; 0]);
|
||||
/**
|
||||
* BlockingResourceBase
|
||||
* Base class of resources that might block clients trying to acquire them.
|
||||
* Does debugging and deadlock detection in DEBUG builds.
|
||||
**/
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct BlockingResourceBase {
|
||||
pub _address: u8,
|
||||
}
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum BlockingResourceBase_BlockingResourceType {
|
||||
eMutex = 0,
|
||||
eReentrantMonitor = 1,
|
||||
eCondVar = 2,
|
||||
}
|
||||
extern "C" {
|
||||
#[link_name =
|
||||
"_ZN7mozilla20BlockingResourceBase17kResourceTypeNameE"]
|
||||
pub static mut BlockingResourceBase_kResourceTypeName:
|
||||
[*const ::std::os::raw::c_char; 0usize];
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_BlockingResourceBase() {
|
||||
assert_eq!(::std::mem::size_of::<BlockingResourceBase>() , 1usize
|
||||
, concat ! (
|
||||
"Size of: " , stringify ! ( BlockingResourceBase ) ));
|
||||
assert_eq! (::std::mem::align_of::<BlockingResourceBase>() ,
|
||||
1usize , concat ! (
|
||||
"Alignment of " , stringify ! ( BlockingResourceBase )
|
||||
));
|
||||
}
|
||||
/**
|
||||
* OffTheBooksMutex is identical to Mutex, except that OffTheBooksMutex doesn't
|
||||
* include leak checking. Sometimes you want to intentionally "leak" a mutex
|
||||
* until shutdown; in these cases, OffTheBooksMutex is for you.
|
||||
*/
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct OffTheBooksMutex {
|
||||
pub _base: root::mozilla::detail::MutexImpl,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_OffTheBooksMutex() {
|
||||
assert_eq!(::std::mem::size_of::<OffTheBooksMutex>() , 40usize ,
|
||||
concat ! (
|
||||
"Size of: " , stringify ! ( OffTheBooksMutex ) ));
|
||||
assert_eq! (::std::mem::align_of::<OffTheBooksMutex>() , 8usize ,
|
||||
concat ! (
|
||||
"Alignment of " , stringify ! ( OffTheBooksMutex ) ));
|
||||
}
|
||||
/**
|
||||
* Mutex
|
||||
* When possible, use MutexAutoLock/MutexAutoUnlock to lock/unlock this
|
||||
* mutex within a scope, instead of calling Lock/Unlock directly.
|
||||
*/
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct Mutex {
|
||||
pub _base: root::mozilla::OffTheBooksMutex,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_Mutex() {
|
||||
assert_eq!(::std::mem::size_of::<Mutex>() , 40usize , concat ! (
|
||||
"Size of: " , stringify ! ( Mutex ) ));
|
||||
assert_eq! (::std::mem::align_of::<Mutex>() , 8usize , concat ! (
|
||||
"Alignment of " , stringify ! ( Mutex ) ));
|
||||
}
|
||||
pub mod image {
|
||||
#[allow(unused_imports)]
|
||||
use self::super::super::super::root;
|
||||
|
@ -8185,12 +8181,6 @@ pub mod root {
|
|||
pub type pair_first_type<_T1> = _T1;
|
||||
pub type pair_second_type<_T2> = _T2;
|
||||
#[repr(C)]
|
||||
pub struct atomic<_Tp> {
|
||||
pub _base: (),
|
||||
pub _phantom_0: ::std::marker::PhantomData<_Tp>,
|
||||
}
|
||||
pub type atomic___base = [u8; 0usize];
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
pub struct input_iterator_tag {
|
||||
pub _address: u8,
|
||||
|
@ -8209,62 +8199,6 @@ pub mod root {
|
|||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
pub struct forward_iterator_tag {
|
||||
pub _address: u8,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_forward_iterator_tag() {
|
||||
assert_eq!(::std::mem::size_of::<forward_iterator_tag>() , 1usize
|
||||
, concat ! (
|
||||
"Size of: " , stringify ! ( forward_iterator_tag ) ));
|
||||
assert_eq! (::std::mem::align_of::<forward_iterator_tag>() ,
|
||||
1usize , concat ! (
|
||||
"Alignment of " , stringify ! ( forward_iterator_tag )
|
||||
));
|
||||
}
|
||||
impl Clone for forward_iterator_tag {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
pub struct bidirectional_iterator_tag {
|
||||
pub _address: u8,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_bidirectional_iterator_tag() {
|
||||
assert_eq!(::std::mem::size_of::<bidirectional_iterator_tag>() ,
|
||||
1usize , concat ! (
|
||||
"Size of: " , stringify ! ( bidirectional_iterator_tag
|
||||
) ));
|
||||
assert_eq! (::std::mem::align_of::<bidirectional_iterator_tag>() ,
|
||||
1usize , concat ! (
|
||||
"Alignment of " , stringify ! (
|
||||
bidirectional_iterator_tag ) ));
|
||||
}
|
||||
impl Clone for bidirectional_iterator_tag {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
pub struct random_access_iterator_tag {
|
||||
pub _address: u8,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_random_access_iterator_tag() {
|
||||
assert_eq!(::std::mem::size_of::<random_access_iterator_tag>() ,
|
||||
1usize , concat ! (
|
||||
"Size of: " , stringify ! ( random_access_iterator_tag
|
||||
) ));
|
||||
assert_eq! (::std::mem::align_of::<random_access_iterator_tag>() ,
|
||||
1usize , concat ! (
|
||||
"Alignment of " , stringify ! (
|
||||
random_access_iterator_tag ) ));
|
||||
}
|
||||
impl Clone for random_access_iterator_tag {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct iterator<_Category, _Tp, _Distance, _Pointer, _Reference> {
|
||||
pub _address: u8,
|
||||
|
@ -8274,22 +8208,22 @@ pub mod root {
|
|||
pub _phantom_3: ::std::marker::PhantomData<_Pointer>,
|
||||
pub _phantom_4: ::std::marker::PhantomData<_Reference>,
|
||||
}
|
||||
pub type iterator_iterator_category<_Category> = _Category;
|
||||
pub type iterator_value_type<_Tp> = _Tp;
|
||||
pub type iterator_difference_type<_Distance> = _Distance;
|
||||
pub type iterator_pointer<_Pointer> = _Pointer;
|
||||
pub type iterator_reference<_Reference> = _Reference;
|
||||
pub type iterator_iterator_category<_Category> = _Category;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct __bit_const_reference<_Cp> {
|
||||
pub __seg_: root::std::__bit_const_reference___storage_pointer<_Cp>,
|
||||
pub __mask_: root::std::__bit_const_reference___storage_type<_Cp>,
|
||||
#[derive(Debug)]
|
||||
pub struct atomic<_Tp> {
|
||||
pub _M_i: _Tp,
|
||||
}
|
||||
pub type __bit_const_reference___storage_type<_Cp> = _Cp;
|
||||
pub type __bit_const_reference___storage_pointer<_Cp> = _Cp;
|
||||
}
|
||||
pub type __darwin_va_list = root::__builtin_va_list;
|
||||
pub type va_list = root::__darwin_va_list;
|
||||
pub mod __gnu_cxx {
|
||||
#[allow(unused_imports)]
|
||||
use self::super::super::root;
|
||||
}
|
||||
pub type va_list = root::__builtin_va_list;
|
||||
/**
|
||||
* MozRefCountType is Mozilla's reference count type.
|
||||
*
|
||||
|
@ -11754,7 +11688,7 @@ pub mod root {
|
|||
eImageBitmapRenderingContext_TransferImageBitmap = 39,
|
||||
eURLCreateObjectURL_MediaStream = 40,
|
||||
eXMLBaseAttribute = 41,
|
||||
eXMLBaseAttributeWithStyledElement = 42,
|
||||
eXMLBaseAttributeForStyleAttr = 42,
|
||||
eDeprecatedOperationCount = 43,
|
||||
}
|
||||
#[repr(u32)]
|
||||
|
@ -12257,30 +12191,6 @@ pub mod root {
|
|||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct nsISelection([u8; 0]);
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
pub struct mozIDOMWindowProxy {
|
||||
pub _base: root::nsISupports,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct mozIDOMWindowProxy_COMTypeInfo<T, U> {
|
||||
pub _address: u8,
|
||||
pub _phantom_0: ::std::marker::PhantomData<T>,
|
||||
pub _phantom_1: ::std::marker::PhantomData<U>,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_mozIDOMWindowProxy() {
|
||||
assert_eq!(::std::mem::size_of::<mozIDOMWindowProxy>() , 8usize ,
|
||||
concat ! ( "Size of: " , stringify ! ( mozIDOMWindowProxy )
|
||||
));
|
||||
assert_eq! (::std::mem::align_of::<mozIDOMWindowProxy>() , 8usize ,
|
||||
concat ! (
|
||||
"Alignment of " , stringify ! ( mozIDOMWindowProxy ) ));
|
||||
}
|
||||
impl Clone for mozIDOMWindowProxy {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct nsPresContext {
|
||||
pub _base: root::nsIObserver,
|
||||
|
@ -13303,125 +13213,12 @@ pub mod root {
|
|||
! ( "Alignment of " , stringify ! ( ErrorNote ) ));
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
pub struct nsIChannel {
|
||||
pub _base: root::nsIRequest,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct nsIChannel_COMTypeInfo<T, U> {
|
||||
pub _address: u8,
|
||||
pub _phantom_0: ::std::marker::PhantomData<T>,
|
||||
pub _phantom_1: ::std::marker::PhantomData<U>,
|
||||
}
|
||||
pub const nsIChannel_LOAD_DOCUMENT_URI: root::nsIChannel__bindgen_ty_1 =
|
||||
nsIChannel__bindgen_ty_1::LOAD_DOCUMENT_URI;
|
||||
pub const nsIChannel_LOAD_RETARGETED_DOCUMENT_URI:
|
||||
root::nsIChannel__bindgen_ty_1 =
|
||||
nsIChannel__bindgen_ty_1::LOAD_RETARGETED_DOCUMENT_URI;
|
||||
pub const nsIChannel_LOAD_REPLACE: root::nsIChannel__bindgen_ty_1 =
|
||||
nsIChannel__bindgen_ty_1::LOAD_REPLACE;
|
||||
pub const nsIChannel_LOAD_INITIAL_DOCUMENT_URI:
|
||||
root::nsIChannel__bindgen_ty_1 =
|
||||
nsIChannel__bindgen_ty_1::LOAD_INITIAL_DOCUMENT_URI;
|
||||
pub const nsIChannel_LOAD_TARGETED: root::nsIChannel__bindgen_ty_1 =
|
||||
nsIChannel__bindgen_ty_1::LOAD_TARGETED;
|
||||
pub const nsIChannel_LOAD_CALL_CONTENT_SNIFFERS:
|
||||
root::nsIChannel__bindgen_ty_1 =
|
||||
nsIChannel__bindgen_ty_1::LOAD_CALL_CONTENT_SNIFFERS;
|
||||
pub const nsIChannel_LOAD_CLASSIFY_URI: root::nsIChannel__bindgen_ty_1 =
|
||||
nsIChannel__bindgen_ty_1::LOAD_CLASSIFY_URI;
|
||||
pub const nsIChannel_LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE:
|
||||
root::nsIChannel__bindgen_ty_1 =
|
||||
nsIChannel__bindgen_ty_1::LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE;
|
||||
pub const nsIChannel_LOAD_EXPLICIT_CREDENTIALS:
|
||||
root::nsIChannel__bindgen_ty_1 =
|
||||
nsIChannel__bindgen_ty_1::LOAD_EXPLICIT_CREDENTIALS;
|
||||
pub const nsIChannel_LOAD_BYPASS_SERVICE_WORKER:
|
||||
root::nsIChannel__bindgen_ty_1 =
|
||||
nsIChannel__bindgen_ty_1::LOAD_BYPASS_SERVICE_WORKER;
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum nsIChannel__bindgen_ty_1 {
|
||||
LOAD_DOCUMENT_URI = 65536,
|
||||
LOAD_RETARGETED_DOCUMENT_URI = 131072,
|
||||
LOAD_REPLACE = 262144,
|
||||
LOAD_INITIAL_DOCUMENT_URI = 524288,
|
||||
LOAD_TARGETED = 1048576,
|
||||
LOAD_CALL_CONTENT_SNIFFERS = 2097152,
|
||||
LOAD_CLASSIFY_URI = 4194304,
|
||||
LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE = 8388608,
|
||||
LOAD_EXPLICIT_CREDENTIALS = 16777216,
|
||||
LOAD_BYPASS_SERVICE_WORKER = 33554432,
|
||||
}
|
||||
pub const nsIChannel_DISPOSITION_INLINE: root::nsIChannel__bindgen_ty_2 =
|
||||
nsIChannel__bindgen_ty_2::DISPOSITION_INLINE;
|
||||
pub const nsIChannel_DISPOSITION_ATTACHMENT:
|
||||
root::nsIChannel__bindgen_ty_2 =
|
||||
nsIChannel__bindgen_ty_2::DISPOSITION_ATTACHMENT;
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum nsIChannel__bindgen_ty_2 {
|
||||
DISPOSITION_INLINE = 0,
|
||||
DISPOSITION_ATTACHMENT = 1,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_nsIChannel() {
|
||||
assert_eq!(::std::mem::size_of::<nsIChannel>() , 8usize , concat ! (
|
||||
"Size of: " , stringify ! ( nsIChannel ) ));
|
||||
assert_eq! (::std::mem::align_of::<nsIChannel>() , 8usize , concat ! (
|
||||
"Alignment of " , stringify ! ( nsIChannel ) ));
|
||||
}
|
||||
impl Clone for nsIChannel {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
pub struct nsILoadContext {
|
||||
pub _base: root::nsISupports,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct nsILoadContext_COMTypeInfo<T, U> {
|
||||
pub _address: u8,
|
||||
pub _phantom_0: ::std::marker::PhantomData<T>,
|
||||
pub _phantom_1: ::std::marker::PhantomData<U>,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_nsILoadContext() {
|
||||
assert_eq!(::std::mem::size_of::<nsILoadContext>() , 8usize , concat !
|
||||
( "Size of: " , stringify ! ( nsILoadContext ) ));
|
||||
assert_eq! (::std::mem::align_of::<nsILoadContext>() , 8usize , concat
|
||||
! ( "Alignment of " , stringify ! ( nsILoadContext ) ));
|
||||
}
|
||||
impl Clone for nsILoadContext {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
pub struct nsIInterfaceRequestor {
|
||||
pub _base: root::nsISupports,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct nsIInterfaceRequestor_COMTypeInfo<T, U> {
|
||||
pub _address: u8,
|
||||
pub _phantom_0: ::std::marker::PhantomData<T>,
|
||||
pub _phantom_1: ::std::marker::PhantomData<U>,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_nsIInterfaceRequestor() {
|
||||
assert_eq!(::std::mem::size_of::<nsIInterfaceRequestor>() , 8usize ,
|
||||
concat ! (
|
||||
"Size of: " , stringify ! ( nsIInterfaceRequestor ) ));
|
||||
assert_eq! (::std::mem::align_of::<nsIInterfaceRequestor>() , 8usize ,
|
||||
concat ! (
|
||||
"Alignment of " , stringify ! ( nsIInterfaceRequestor )
|
||||
));
|
||||
}
|
||||
impl Clone for nsIInterfaceRequestor {
|
||||
fn clone(&self) -> Self { *self }
|
||||
pub enum nsCompatibility {
|
||||
eCompatibility_FullStandards = 1,
|
||||
eCompatibility_AlmostStandards = 2,
|
||||
eCompatibility_NavQuirks = 3,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
|
@ -13770,6 +13567,82 @@ pub mod root {
|
|||
"Alignment of field: " , stringify ! ( nsINode ) , "::" ,
|
||||
stringify ! ( mSlots ) ));
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
pub struct nsIChannel {
|
||||
pub _base: root::nsIRequest,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct nsIChannel_COMTypeInfo<T, U> {
|
||||
pub _address: u8,
|
||||
pub _phantom_0: ::std::marker::PhantomData<T>,
|
||||
pub _phantom_1: ::std::marker::PhantomData<U>,
|
||||
}
|
||||
pub const nsIChannel_LOAD_DOCUMENT_URI: root::nsIChannel__bindgen_ty_1 =
|
||||
nsIChannel__bindgen_ty_1::LOAD_DOCUMENT_URI;
|
||||
pub const nsIChannel_LOAD_RETARGETED_DOCUMENT_URI:
|
||||
root::nsIChannel__bindgen_ty_1 =
|
||||
nsIChannel__bindgen_ty_1::LOAD_RETARGETED_DOCUMENT_URI;
|
||||
pub const nsIChannel_LOAD_REPLACE: root::nsIChannel__bindgen_ty_1 =
|
||||
nsIChannel__bindgen_ty_1::LOAD_REPLACE;
|
||||
pub const nsIChannel_LOAD_INITIAL_DOCUMENT_URI:
|
||||
root::nsIChannel__bindgen_ty_1 =
|
||||
nsIChannel__bindgen_ty_1::LOAD_INITIAL_DOCUMENT_URI;
|
||||
pub const nsIChannel_LOAD_TARGETED: root::nsIChannel__bindgen_ty_1 =
|
||||
nsIChannel__bindgen_ty_1::LOAD_TARGETED;
|
||||
pub const nsIChannel_LOAD_CALL_CONTENT_SNIFFERS:
|
||||
root::nsIChannel__bindgen_ty_1 =
|
||||
nsIChannel__bindgen_ty_1::LOAD_CALL_CONTENT_SNIFFERS;
|
||||
pub const nsIChannel_LOAD_CLASSIFY_URI: root::nsIChannel__bindgen_ty_1 =
|
||||
nsIChannel__bindgen_ty_1::LOAD_CLASSIFY_URI;
|
||||
pub const nsIChannel_LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE:
|
||||
root::nsIChannel__bindgen_ty_1 =
|
||||
nsIChannel__bindgen_ty_1::LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE;
|
||||
pub const nsIChannel_LOAD_EXPLICIT_CREDENTIALS:
|
||||
root::nsIChannel__bindgen_ty_1 =
|
||||
nsIChannel__bindgen_ty_1::LOAD_EXPLICIT_CREDENTIALS;
|
||||
pub const nsIChannel_LOAD_BYPASS_SERVICE_WORKER:
|
||||
root::nsIChannel__bindgen_ty_1 =
|
||||
nsIChannel__bindgen_ty_1::LOAD_BYPASS_SERVICE_WORKER;
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum nsIChannel__bindgen_ty_1 {
|
||||
LOAD_DOCUMENT_URI = 65536,
|
||||
LOAD_RETARGETED_DOCUMENT_URI = 131072,
|
||||
LOAD_REPLACE = 262144,
|
||||
LOAD_INITIAL_DOCUMENT_URI = 524288,
|
||||
LOAD_TARGETED = 1048576,
|
||||
LOAD_CALL_CONTENT_SNIFFERS = 2097152,
|
||||
LOAD_CLASSIFY_URI = 4194304,
|
||||
LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE = 8388608,
|
||||
LOAD_EXPLICIT_CREDENTIALS = 16777216,
|
||||
LOAD_BYPASS_SERVICE_WORKER = 33554432,
|
||||
}
|
||||
pub const nsIChannel_DISPOSITION_INLINE: root::nsIChannel__bindgen_ty_2 =
|
||||
nsIChannel__bindgen_ty_2::DISPOSITION_INLINE;
|
||||
pub const nsIChannel_DISPOSITION_ATTACHMENT:
|
||||
root::nsIChannel__bindgen_ty_2 =
|
||||
nsIChannel__bindgen_ty_2::DISPOSITION_ATTACHMENT;
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum nsIChannel__bindgen_ty_2 {
|
||||
DISPOSITION_INLINE = 0,
|
||||
DISPOSITION_ATTACHMENT = 1,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_nsIChannel() {
|
||||
assert_eq!(::std::mem::size_of::<nsIChannel>() , 8usize , concat ! (
|
||||
"Size of: " , stringify ! ( nsIChannel ) ));
|
||||
assert_eq! (::std::mem::align_of::<nsIChannel>() , 8usize , concat ! (
|
||||
"Alignment of " , stringify ! ( nsIChannel ) ));
|
||||
}
|
||||
impl Clone for nsIChannel {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct nsILoadContext([u8; 0]);
|
||||
pub type nsSecurityFlags = u32;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
|
@ -13878,6 +13751,31 @@ pub mod root {
|
|||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
pub struct nsIInterfaceRequestor {
|
||||
pub _base: root::nsISupports,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct nsIInterfaceRequestor_COMTypeInfo<T, U> {
|
||||
pub _address: u8,
|
||||
pub _phantom_0: ::std::marker::PhantomData<T>,
|
||||
pub _phantom_1: ::std::marker::PhantomData<U>,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_nsIInterfaceRequestor() {
|
||||
assert_eq!(::std::mem::size_of::<nsIInterfaceRequestor>() , 8usize ,
|
||||
concat ! (
|
||||
"Size of: " , stringify ! ( nsIInterfaceRequestor ) ));
|
||||
assert_eq! (::std::mem::align_of::<nsIInterfaceRequestor>() , 8usize ,
|
||||
concat ! (
|
||||
"Alignment of " , stringify ! ( nsIInterfaceRequestor )
|
||||
));
|
||||
}
|
||||
impl Clone for nsIInterfaceRequestor {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct nsIInputStream([u8; 0]);
|
||||
#[repr(C)]
|
||||
|
@ -13904,13 +13802,6 @@ pub mod root {
|
|||
impl Clone for nsIStreamListener {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum nsCompatibility {
|
||||
eCompatibility_FullStandards = 1,
|
||||
eCompatibility_AlmostStandards = 2,
|
||||
eCompatibility_NavQuirks = 3,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct nsAttrValue {
|
||||
|
@ -15159,63 +15050,66 @@ pub mod root {
|
|||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct nsDOMMutationObserver([u8; 0]);
|
||||
pub const NODE_HAS_LISTENERMANAGER: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_HAS_LISTENERMANAGER;
|
||||
pub const NODE_HAS_PROPERTIES: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_HAS_PROPERTIES;
|
||||
pub const NODE_IS_ANONYMOUS_ROOT: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_IS_ANONYMOUS_ROOT;
|
||||
pub const NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
|
||||
pub const NODE_IS_NATIVE_ANONYMOUS_ROOT: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_IS_NATIVE_ANONYMOUS_ROOT;
|
||||
pub const NODE_FORCE_XBL_BINDINGS: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_FORCE_XBL_BINDINGS;
|
||||
pub const NODE_MAY_BE_IN_BINDING_MNGR: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_MAY_BE_IN_BINDING_MNGR;
|
||||
pub const NODE_IS_EDITABLE: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_IS_EDITABLE;
|
||||
pub const NODE_IS_NATIVE_ANONYMOUS: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_IS_NATIVE_ANONYMOUS;
|
||||
pub const NODE_IS_IN_SHADOW_TREE: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_IS_IN_SHADOW_TREE;
|
||||
pub const NODE_HAS_EMPTY_SELECTOR: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_HAS_EMPTY_SELECTOR;
|
||||
pub const NODE_HAS_SLOW_SELECTOR: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_HAS_SLOW_SELECTOR;
|
||||
pub const NODE_HAS_EDGE_CHILD_SELECTOR: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_HAS_EDGE_CHILD_SELECTOR;
|
||||
pub const NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS;
|
||||
pub const NODE_ALL_SELECTOR_FLAGS: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_ALL_SELECTOR_FLAGS;
|
||||
pub const NODE_NEEDS_FRAME: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_NEEDS_FRAME;
|
||||
pub const NODE_DESCENDANTS_NEED_FRAMES: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_DESCENDANTS_NEED_FRAMES;
|
||||
pub const NODE_HAS_ACCESSKEY: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_HAS_ACCESSKEY;
|
||||
pub const NODE_HAS_DIRECTION_RTL: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_HAS_DIRECTION_RTL;
|
||||
pub const NODE_HAS_DIRECTION_LTR: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_HAS_DIRECTION_LTR;
|
||||
pub const NODE_ALL_DIRECTION_FLAGS: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_ALL_DIRECTION_FLAGS;
|
||||
pub const NODE_CHROME_ONLY_ACCESS: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_CHROME_ONLY_ACCESS;
|
||||
pub const NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS;
|
||||
pub const NODE_SHARED_RESTYLE_BIT_1: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_SHARED_RESTYLE_BIT_1;
|
||||
pub const NODE_SHARED_RESTYLE_BIT_2: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_SHARED_RESTYLE_BIT_2;
|
||||
pub const NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_SHARED_RESTYLE_BIT_1;
|
||||
pub const NODE_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_28 =
|
||||
_bindgen_ty_28::NODE_TYPE_SPECIFIC_BITS_OFFSET;
|
||||
pub const NODE_HAS_LISTENERMANAGER: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_HAS_LISTENERMANAGER;
|
||||
pub const NODE_HAS_PROPERTIES: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_HAS_PROPERTIES;
|
||||
pub const NODE_IS_ANONYMOUS_ROOT: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_IS_ANONYMOUS_ROOT;
|
||||
pub const NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
|
||||
pub const NODE_IS_NATIVE_ANONYMOUS_ROOT: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_IS_NATIVE_ANONYMOUS_ROOT;
|
||||
pub const NODE_FORCE_XBL_BINDINGS: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_FORCE_XBL_BINDINGS;
|
||||
pub const NODE_MAY_BE_IN_BINDING_MNGR: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_MAY_BE_IN_BINDING_MNGR;
|
||||
pub const NODE_IS_EDITABLE: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_IS_EDITABLE;
|
||||
pub const NODE_IS_NATIVE_ANONYMOUS: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_IS_NATIVE_ANONYMOUS;
|
||||
pub const NODE_IS_IN_SHADOW_TREE: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_IS_IN_SHADOW_TREE;
|
||||
pub const NODE_HAS_EMPTY_SELECTOR: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_HAS_EMPTY_SELECTOR;
|
||||
pub const NODE_HAS_SLOW_SELECTOR: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_HAS_SLOW_SELECTOR;
|
||||
pub const NODE_HAS_EDGE_CHILD_SELECTOR: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_HAS_EDGE_CHILD_SELECTOR;
|
||||
pub const NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS;
|
||||
pub const NODE_ALL_SELECTOR_FLAGS: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_ALL_SELECTOR_FLAGS;
|
||||
pub const NODE_NEEDS_FRAME: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_NEEDS_FRAME;
|
||||
pub const NODE_DESCENDANTS_NEED_FRAMES: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_DESCENDANTS_NEED_FRAMES;
|
||||
pub const NODE_HAS_ACCESSKEY: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_HAS_ACCESSKEY;
|
||||
pub const NODE_HAS_DIRECTION_RTL: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_HAS_DIRECTION_RTL;
|
||||
pub const NODE_HAS_DIRECTION_LTR: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_HAS_DIRECTION_LTR;
|
||||
pub const NODE_ALL_DIRECTION_FLAGS: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_ALL_DIRECTION_FLAGS;
|
||||
pub const NODE_CHROME_ONLY_ACCESS: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_CHROME_ONLY_ACCESS;
|
||||
pub const NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS;
|
||||
pub const NODE_SHARED_RESTYLE_BIT_1: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_SHARED_RESTYLE_BIT_1;
|
||||
pub const NODE_SHARED_RESTYLE_BIT_2: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_SHARED_RESTYLE_BIT_2;
|
||||
pub const NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_SHARED_RESTYLE_BIT_1;
|
||||
pub const NODE_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO:
|
||||
root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_SHARED_RESTYLE_BIT_2;
|
||||
pub const NODE_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_105 =
|
||||
_bindgen_ty_105::NODE_TYPE_SPECIFIC_BITS_OFFSET;
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum _bindgen_ty_28 {
|
||||
pub enum _bindgen_ty_105 {
|
||||
NODE_HAS_LISTENERMANAGER = 4,
|
||||
NODE_HAS_PROPERTIES = 8,
|
||||
NODE_IS_ANONYMOUS_ROOT = 16,
|
||||
|
@ -22096,7 +21990,7 @@ pub mod root {
|
|||
pub type imgRequest_HasThreadSafeRefCnt = root::mozilla::TrueType;
|
||||
#[test]
|
||||
fn bindgen_test_layout_imgRequest() {
|
||||
assert_eq!(::std::mem::size_of::<imgRequest>() , 400usize , concat ! (
|
||||
assert_eq!(::std::mem::size_of::<imgRequest>() , 376usize , concat ! (
|
||||
"Size of: " , stringify ! ( imgRequest ) ));
|
||||
assert_eq! (::std::mem::align_of::<imgRequest>() , 8usize , concat ! (
|
||||
"Alignment of " , stringify ! ( imgRequest ) ));
|
||||
|
|
|
@ -17,7 +17,7 @@ use data::{ComputedStyle, ElementData, ElementStyles, RestyleData};
|
|||
use dom::{AnimationRules, SendElement, TElement, TNode};
|
||||
use properties::{CascadeFlags, ComputedValues, SHAREABLE, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, cascade};
|
||||
use properties::longhands::display::computed_value as display;
|
||||
use restyle_hints::{RESTYLE_STYLE_ATTRIBUTE, RestyleHint};
|
||||
use restyle_hints::{RESTYLE_STYLE_ATTRIBUTE, RESTYLE_CSS_ANIMATIONS, RestyleHint};
|
||||
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode};
|
||||
use selector_parser::{PseudoElement, RestyleDamage, SelectorImpl};
|
||||
use selectors::MatchAttr;
|
||||
|
@ -954,30 +954,54 @@ pub trait MatchMethods : TElement {
|
|||
context: &StyleContext<Self>,
|
||||
data: &mut AtomicRefMut<ElementData>)
|
||||
-> bool {
|
||||
let primary_rules = &mut data.styles_mut().primary.rules;
|
||||
use properties::PropertyDeclarationBlock;
|
||||
use shared_lock::Locked;
|
||||
|
||||
let element_styles = &mut data.styles_mut();
|
||||
let primary_rules = &mut element_styles.primary.rules;
|
||||
let mut rule_node_changed = false;
|
||||
|
||||
if hint.contains(RESTYLE_STYLE_ATTRIBUTE) {
|
||||
let style_attribute = self.style_attribute();
|
||||
{
|
||||
let mut replace_rule_node = |level: CascadeLevel,
|
||||
pdb: Option<&Arc<Locked<PropertyDeclarationBlock>>>,
|
||||
path: &mut StrongRuleNode| {
|
||||
let new_node = context.shared.stylist.rule_tree
|
||||
.update_rule_at_level(level, pdb, path, &context.shared.guards);
|
||||
if let Some(n) = new_node {
|
||||
*path = n;
|
||||
rule_node_changed = true;
|
||||
}
|
||||
};
|
||||
|
||||
let new_node = context.shared.stylist.rule_tree
|
||||
.update_rule_at_level(CascadeLevel::StyleAttributeNormal,
|
||||
style_attribute,
|
||||
primary_rules,
|
||||
&context.shared.guards);
|
||||
if let Some(n) = new_node {
|
||||
*primary_rules = n;
|
||||
rule_node_changed = true;
|
||||
}
|
||||
// RESTYLE_CSS_ANIMATIONS is processed prior to other restyle hints
|
||||
// in the name of animation-only traversal. Rest of restyle hints
|
||||
// will be processed in a subsequent normal traversal.
|
||||
if hint.contains(RESTYLE_CSS_ANIMATIONS) {
|
||||
debug_assert!(context.shared.animation_only_restyle);
|
||||
|
||||
let new_node = context.shared.stylist.rule_tree
|
||||
.update_rule_at_level(CascadeLevel::StyleAttributeImportant,
|
||||
style_attribute,
|
||||
primary_rules,
|
||||
&context.shared.guards);
|
||||
if let Some(n) = new_node {
|
||||
*primary_rules = n;
|
||||
rule_node_changed = true;
|
||||
let animation_rule = self.get_animation_rule(None);
|
||||
replace_rule_node(CascadeLevel::Animations,
|
||||
animation_rule.as_ref(),
|
||||
primary_rules);
|
||||
|
||||
let iter = element_styles.pseudos.iter_mut().filter(|&(p, _)|
|
||||
<Self as MatchAttr>::Impl::pseudo_is_before_or_after(p));
|
||||
for (pseudo, ref mut computed) in iter {
|
||||
let animation_rule = self.get_animation_rule(Some(pseudo));
|
||||
let pseudo_rules = &mut computed.rules;
|
||||
replace_rule_node(CascadeLevel::Animations,
|
||||
animation_rule.as_ref(),
|
||||
pseudo_rules);
|
||||
}
|
||||
} else if hint.contains(RESTYLE_STYLE_ATTRIBUTE) {
|
||||
let style_attribute = self.style_attribute();
|
||||
replace_rule_node(CascadeLevel::StyleAttributeNormal,
|
||||
style_attribute,
|
||||
primary_rules);
|
||||
replace_rule_node(CascadeLevel::StyleAttributeImportant,
|
||||
style_attribute,
|
||||
primary_rules);
|
||||
// The per-pseudo rule nodes never change in this path.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -269,6 +269,10 @@
|
|||
|
||||
impl ToCss for SpecifiedValue {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
if self.0.is_empty() {
|
||||
return dest.write_str("none");
|
||||
}
|
||||
|
||||
let mut first = true;
|
||||
for pair in &self.0 {
|
||||
if !first {
|
||||
|
@ -278,6 +282,7 @@
|
|||
try!(serialize_identifier(&pair.0, dest));
|
||||
try!(write!(dest, " {}", pair.1));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,7 +92,9 @@ ${helpers.predefined_type("stroke-opacity", "Opacity", "1.0",
|
|||
products="gecko", animatable=False,
|
||||
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeOpacityProperty")}
|
||||
|
||||
${helpers.predefined_type("stroke-dasharray", "LoPOrNumber", "Either::Second(0.0)",
|
||||
${helpers.predefined_type("stroke-dasharray",
|
||||
"LengthOrPercentageOrNumber",
|
||||
"Either::Second(0.0)",
|
||||
"parse_non_negative",
|
||||
vector="True",
|
||||
products="gecko",
|
||||
|
|
|
@ -47,6 +47,11 @@ bitflags! {
|
|||
/// of their descendants.
|
||||
const RESTYLE_LATER_SIBLINGS = 0x08,
|
||||
|
||||
/// Replace the style data coming from CSS animations without updating
|
||||
/// any other style data. This hint is only processed in animation-only
|
||||
/// traversal which is prior to normal traversal.
|
||||
const RESTYLE_CSS_ANIMATIONS = 0x20,
|
||||
|
||||
/// Don't re-run selector-matching on the element, only the style
|
||||
/// attribute has changed, and this change didn't have any other
|
||||
/// dependencies.
|
||||
|
@ -81,6 +86,7 @@ pub fn assert_restyle_hints_match() {
|
|||
// (RESTYLE_SELF | RESTYLE_DESCENDANTS).
|
||||
nsRestyleHint_eRestyle_Subtree => RESTYLE_DESCENDANTS,
|
||||
nsRestyleHint_eRestyle_LaterSiblings => RESTYLE_LATER_SIBLINGS,
|
||||
nsRestyleHint_eRestyle_CSSAnimations => RESTYLE_CSS_ANIMATIONS,
|
||||
nsRestyleHint_eRestyle_StyleAttribute => RESTYLE_STYLE_ATTRIBUTE,
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +95,7 @@ impl RestyleHint {
|
|||
/// The subset hints that affect the styling of a single element during the
|
||||
/// traversal.
|
||||
pub fn for_self() -> Self {
|
||||
RESTYLE_SELF | RESTYLE_STYLE_ATTRIBUTE
|
||||
RESTYLE_SELF | RESTYLE_STYLE_ATTRIBUTE | RESTYLE_CSS_ANIMATIONS
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,28 @@ pub struct PerLevelTraversalData {
|
|||
pub current_dom_depth: Option<usize>,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Represents that target elements of the traversal.
|
||||
pub flags TraversalFlags: u8 {
|
||||
/// Traverse only unstyled children.
|
||||
const UNSTYLED_CHILDREN_ONLY = 0x01,
|
||||
/// Traverse only elements for animation restyles
|
||||
const ANIMATION_ONLY = 0x02,
|
||||
}
|
||||
}
|
||||
|
||||
impl TraversalFlags {
|
||||
/// Returns true if the traversal is for animation-only restyles.
|
||||
pub fn for_animation_only(&self) -> bool {
|
||||
self.contains(ANIMATION_ONLY)
|
||||
}
|
||||
|
||||
/// Returns true if the traversal is for unstyled children.
|
||||
pub fn for_unstyled_children_only(&self) -> bool {
|
||||
self.contains(UNSTYLED_CHILDREN_ONLY)
|
||||
}
|
||||
}
|
||||
|
||||
/// This structure exists to enforce that callers invoke pre_traverse, and also
|
||||
/// to pass information from the pre-traversal into the primary traversal.
|
||||
pub struct PreTraverseToken {
|
||||
|
@ -109,12 +131,15 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
/// a traversal is needed. Returns a token that allows the caller to prove
|
||||
/// that the call happened.
|
||||
///
|
||||
/// The unstyled_children_only parameter is used in Gecko to style newly-
|
||||
/// The traversal_flag is used in Gecko.
|
||||
/// If traversal_flag::UNSTYLED_CHILDREN_ONLY is specified, style newly-
|
||||
/// appended children without restyling the parent.
|
||||
fn pre_traverse(root: E, stylist: &Stylist, unstyled_children_only: bool)
|
||||
/// If traversal_flag::ANIMATION_ONLY is specified, style only elements for
|
||||
/// animations.
|
||||
fn pre_traverse(root: E, stylist: &Stylist, traversal_flags: TraversalFlags)
|
||||
-> PreTraverseToken
|
||||
{
|
||||
if unstyled_children_only {
|
||||
if traversal_flags.for_unstyled_children_only() {
|
||||
return PreTraverseToken {
|
||||
traverse: true,
|
||||
unstyled_children_only: true,
|
||||
|
@ -135,7 +160,7 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
}
|
||||
|
||||
PreTraverseToken {
|
||||
traverse: Self::node_needs_traversal(root.as_node()),
|
||||
traverse: Self::node_needs_traversal(root.as_node(), traversal_flags.for_animation_only()),
|
||||
unstyled_children_only: false,
|
||||
}
|
||||
}
|
||||
|
@ -149,7 +174,7 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
}
|
||||
|
||||
/// Returns true if traversal is needed for the given node and subtree.
|
||||
fn node_needs_traversal(node: E::ConcreteNode) -> bool {
|
||||
fn node_needs_traversal(node: E::ConcreteNode, animation_only: bool) -> bool {
|
||||
// Non-incremental layout visits every node.
|
||||
if cfg!(feature = "servo") && opts::get().nonincremental_layout {
|
||||
return true;
|
||||
|
@ -158,6 +183,22 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
match node.as_element() {
|
||||
None => Self::text_node_needs_traversal(node),
|
||||
Some(el) => {
|
||||
// In case of animation-only traversal we need to traverse
|
||||
// the element if the element has animation only dirty
|
||||
// descendants bit, animation-only restyle hint or recascade.
|
||||
if animation_only {
|
||||
if el.has_animation_only_dirty_descendants() {
|
||||
return true;
|
||||
}
|
||||
|
||||
let data = match el.borrow_data() {
|
||||
Some(d) => d,
|
||||
None => return false,
|
||||
};
|
||||
return data.get_restyle()
|
||||
.map_or(false, |r| r.hint.has_animation_hint() || r.recascade);
|
||||
}
|
||||
|
||||
// If the dirty descendants bit is set, we need to traverse no
|
||||
// matter what. Skip examining the ElementData.
|
||||
if el.has_dirty_descendants() {
|
||||
|
@ -270,7 +311,7 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
}
|
||||
|
||||
for kid in parent.as_node().children() {
|
||||
if Self::node_needs_traversal(kid) {
|
||||
if Self::node_needs_traversal(kid, self.shared_context().animation_only_restyle) {
|
||||
let el = kid.as_element();
|
||||
if el.as_ref().and_then(|el| el.borrow_data())
|
||||
.map_or(false, |d| d.has_styles())
|
||||
|
@ -448,21 +489,38 @@ pub fn recalc_style_at<E, D>(traversal: &D,
|
|||
None => empty_hint,
|
||||
Some(r) => {
|
||||
r.recascade = false;
|
||||
mem::replace(&mut r.hint, empty_hint).propagate()
|
||||
if r.hint.has_animation_hint() {
|
||||
debug_assert!(context.shared.animation_only_restyle,
|
||||
"animation restyle hint should be handled during animation-only restyles");
|
||||
// Drop animation restyle hint.
|
||||
let propagated_hint = r.hint.propagate();
|
||||
r.hint.remove_animation_hint();
|
||||
propagated_hint
|
||||
} else {
|
||||
mem::replace(&mut r.hint, empty_hint).propagate()
|
||||
}
|
||||
},
|
||||
};
|
||||
debug_assert!(data.has_current_styles());
|
||||
debug_assert!(data.has_current_styles() || context.shared.animation_only_restyle,
|
||||
"Should have computed style or haven't yet valid computed style in case of animation-only restyle");
|
||||
trace!("propagated_hint={:?}, inherited_style_changed={:?}", propagated_hint, inherited_style_changed);
|
||||
|
||||
// Preprocess children, propagating restyle hints and handling sibling relationships.
|
||||
if traversal.should_traverse_children(&mut context.thread_local, element, &data, DontLog) &&
|
||||
(element.has_dirty_descendants() || !propagated_hint.is_empty() || inherited_style_changed) {
|
||||
((!context.shared.animation_only_restyle && element.has_dirty_descendants()) ||
|
||||
(context.shared.animation_only_restyle && element.has_animation_only_dirty_descendants()) ||
|
||||
!propagated_hint.is_empty() ||
|
||||
inherited_style_changed) {
|
||||
let damage_handled = data.get_restyle().map_or(RestyleDamage::empty(), |r| {
|
||||
r.damage_handled() | r.damage.handled_for_descendants()
|
||||
});
|
||||
preprocess_children(traversal, element, propagated_hint, damage_handled, inherited_style_changed);
|
||||
}
|
||||
|
||||
if context.shared.animation_only_restyle {
|
||||
unsafe { element.unset_animation_only_dirty_descendants(); }
|
||||
}
|
||||
|
||||
// Make sure the dirty descendants bit is not set for the root of a
|
||||
// display:none subtree, even if the style didn't change (since, if
|
||||
// the style did change, we'd have already cleared it above).
|
||||
|
|
|
@ -400,7 +400,7 @@ impl ToCss for SVGPaint {
|
|||
}
|
||||
|
||||
/// <length> | <percentage> | <number>
|
||||
pub type LoPOrNumber = Either<LengthOrPercentage, Number>;
|
||||
pub type LengthOrPercentageOrNumber = Either<LengthOrPercentage, Number>;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
|
|
|
@ -909,15 +909,26 @@ impl ToCss for Percentage {
|
|||
}
|
||||
}
|
||||
|
||||
impl Percentage {
|
||||
fn parse_internal(input: &mut Parser, context: AllowedNumericType) -> Result<Self, ()> {
|
||||
match try!(input.next()) {
|
||||
Token::Percentage(ref value) if context.is_ok(value.unit_value) => {
|
||||
Ok(Percentage(value.unit_value))
|
||||
}
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses a percentage token, but rejects it if it's negative.
|
||||
pub fn parse_non_negative(input: &mut Parser) -> Result<Self, ()> {
|
||||
Self::parse_internal(input, AllowedNumericType::NonNegative)
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for Percentage {
|
||||
#[inline]
|
||||
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||
let context = AllowedNumericType::All;
|
||||
match try!(input.next()) {
|
||||
Token::Percentage(ref value) if context.is_ok(value.unit_value) =>
|
||||
Ok(Percentage(value.unit_value)),
|
||||
_ => Err(())
|
||||
}
|
||||
Self::parse_internal(input, AllowedNumericType::All)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -538,8 +538,8 @@ impl Parse for Number {
|
|||
impl Number {
|
||||
fn parse_with_minimum(input: &mut Parser, min: CSSFloat) -> Result<Number, ()> {
|
||||
match parse_number(input) {
|
||||
Ok(value) if value < min => Err(()),
|
||||
value => value.map(Number),
|
||||
Ok(value) if value >= min => Ok(Number(value)),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -585,13 +585,12 @@ pub enum NumberOrPercentage {
|
|||
no_viewport_percentage!(NumberOrPercentage);
|
||||
|
||||
impl Parse for NumberOrPercentage {
|
||||
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||
if let Ok(per) = input.try(|input| Percentage::parse(context, input)) {
|
||||
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||
if let Ok(per) = input.try(Percentage::parse_non_negative) {
|
||||
return Ok(NumberOrPercentage::Percentage(per));
|
||||
}
|
||||
|
||||
let num = try!(Number::parse_non_negative(input));
|
||||
Ok(NumberOrPercentage::Number(num))
|
||||
Number::parse_non_negative(input).map(NumberOrPercentage::Number)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -980,18 +979,18 @@ impl ToComputedValue for SVGPaintKind {
|
|||
}
|
||||
|
||||
/// <length> | <percentage> | <number>
|
||||
pub type LoPOrNumber = Either<LengthOrPercentage, Number>;
|
||||
pub type LengthOrPercentageOrNumber = Either<LengthOrPercentage, Number>;
|
||||
|
||||
impl LoPOrNumber {
|
||||
impl LengthOrPercentageOrNumber {
|
||||
/// parse a <length-percentage> | <number> enforcing that the contents aren't negative
|
||||
pub fn parse_non_negative(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||
if let Ok(lop) = input.try(LengthOrPercentage::parse_non_negative) {
|
||||
Ok(Either::First(lop))
|
||||
} else if let Ok(num) = input.try(Number::parse_non_negative) {
|
||||
Ok(Either::Second(num))
|
||||
} else {
|
||||
Err(())
|
||||
// NB: Parse numbers before Lengths so we are consistent about how to
|
||||
// recognize and serialize "0".
|
||||
if let Ok(num) = input.try(Number::parse_non_negative) {
|
||||
return Ok(Either::Second(num))
|
||||
}
|
||||
|
||||
LengthOrPercentage::parse_non_negative(input).map(Either::First)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -117,7 +117,12 @@ macro_rules! __define_css_keyword_enum__actual {
|
|||
/// Parse this property from a CSS input stream.
|
||||
pub fn parse(input: &mut ::cssparser::Parser) -> Result<$name, ()> {
|
||||
let ident = input.expect_ident()?;
|
||||
match_ignore_ascii_case! { &ident,
|
||||
Self::from_ident(&ident)
|
||||
}
|
||||
|
||||
/// Parse this property from an already-tokenized identifier.
|
||||
pub fn from_ident(ident: &str) -> Result<$name, ()> {
|
||||
match_ignore_ascii_case! { ident,
|
||||
$( $css => Ok($name::$variant), )+
|
||||
_ => Err(())
|
||||
}
|
||||
|
|
|
@ -47,10 +47,8 @@ impl ServoUrl {
|
|||
Arc::try_unwrap(self.0).unwrap_or_else(|s| (*s).clone()).into_string()
|
||||
}
|
||||
|
||||
// NOTE: These methods return options that are always true temporarily until
|
||||
// we special-case some urls to avoid going through rust-url.
|
||||
pub fn into_url(self) -> Option<Url> {
|
||||
Some(Arc::try_unwrap(self.0).unwrap_or_else(|s| (*s).clone()))
|
||||
pub fn into_url(self) -> Url {
|
||||
Arc::try_unwrap(self.0).unwrap_or_else(|s| (*s).clone())
|
||||
}
|
||||
|
||||
pub fn as_url(&self) -> &Url {
|
||||
|
@ -94,24 +92,24 @@ impl ServoUrl {
|
|||
self.0.as_str()
|
||||
}
|
||||
|
||||
pub fn as_mut_url(&mut self) -> Option<&mut Url> {
|
||||
Some(Arc::make_mut(&mut self.0))
|
||||
pub fn as_mut_url(&mut self) -> &mut Url {
|
||||
Arc::make_mut(&mut self.0)
|
||||
}
|
||||
|
||||
pub fn set_username(&mut self, user: &str) -> Result<(), ()> {
|
||||
Arc::make_mut(&mut self.0).set_username(user)
|
||||
self.as_mut_url().set_username(user)
|
||||
}
|
||||
|
||||
pub fn set_ip_host(&mut self, addr: IpAddr) -> Result<(), ()> {
|
||||
Arc::make_mut(&mut self.0).set_ip_host(addr)
|
||||
self.as_mut_url().set_ip_host(addr)
|
||||
}
|
||||
|
||||
pub fn set_password(&mut self, pass: Option<&str>) -> Result<(), ()> {
|
||||
Arc::make_mut(&mut self.0).set_password(pass)
|
||||
self.as_mut_url().set_password(pass)
|
||||
}
|
||||
|
||||
pub fn set_fragment(&mut self, fragment: Option<&str>) {
|
||||
Arc::make_mut(&mut self.0).set_fragment(fragment)
|
||||
self.as_mut_url().set_fragment(fragment)
|
||||
}
|
||||
|
||||
pub fn username(&self) -> &str {
|
||||
|
|
|
@ -10,6 +10,7 @@ name = "webdriver_server"
|
|||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.4.1"
|
||||
cookie = "0.2.5"
|
||||
euclid = "0.11"
|
||||
hyper = "0.9.9"
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#![deny(unsafe_code)]
|
||||
|
||||
extern crate base64;
|
||||
extern crate cookie as cookie_rs;
|
||||
extern crate euclid;
|
||||
extern crate hyper;
|
||||
|
@ -34,7 +35,6 @@ use keys::keycodes_to_keys;
|
|||
use msg::constellation_msg::{FrameId, PipelineId, TraversalDirection};
|
||||
use net_traits::image::base::PixelFormat;
|
||||
use regex::Captures;
|
||||
use rustc_serialize::base64::{CharacterSet, Config, Newline, ToBase64};
|
||||
use rustc_serialize::json::{Json, ToJson};
|
||||
use script_traits::{ConstellationMsg, LoadData, WebDriverCommandMsg};
|
||||
use script_traits::webdriver_msg::{LoadStatus, WebDriverCookieError, WebDriverFrameId};
|
||||
|
@ -831,13 +831,7 @@ impl Handler {
|
|||
let mut png_data = Vec::new();
|
||||
DynamicImage::ImageRgb8(rgb).save(&mut png_data, ImageFormat::PNG).unwrap();
|
||||
|
||||
let config = Config {
|
||||
char_set: CharacterSet::Standard,
|
||||
newline: Newline::LF,
|
||||
pad: true,
|
||||
line_length: None
|
||||
};
|
||||
let encoded = png_data.to_base64(config);
|
||||
let encoded = base64::encode(&png_data);
|
||||
Ok(WebDriverResponse::Generic(ValueResponse::new(encoded.to_json())))
|
||||
}
|
||||
|
||||
|
|
|
@ -83,7 +83,8 @@ use style::stylesheets::StylesheetLoader as StyleStylesheetLoader;
|
|||
use style::supports::parse_condition_or_declaration;
|
||||
use style::thread_state;
|
||||
use style::timer::Timer;
|
||||
use style::traversal::{resolve_style, DomTraversal, TraversalDriver};
|
||||
use style::traversal::{ANIMATION_ONLY, UNSTYLED_CHILDREN_ONLY};
|
||||
use style::traversal::{resolve_style, DomTraversal, TraversalDriver, TraversalFlags};
|
||||
use style_traits::ToCss;
|
||||
use super::stylesheet_loader::StylesheetLoader;
|
||||
|
||||
|
@ -124,7 +125,8 @@ pub extern "C" fn Servo_Shutdown() {
|
|||
}
|
||||
|
||||
fn create_shared_context<'a>(guard: &'a SharedRwLockReadGuard,
|
||||
per_doc_data: &PerDocumentStyleDataImpl) -> SharedStyleContext<'a> {
|
||||
per_doc_data: &PerDocumentStyleDataImpl,
|
||||
animation_only: bool) -> SharedStyleContext<'a> {
|
||||
let local_context_data =
|
||||
ThreadLocalStyleContextCreationInfo::new(per_doc_data.new_animations_sender.clone());
|
||||
|
||||
|
@ -139,11 +141,12 @@ fn create_shared_context<'a>(guard: &'a SharedRwLockReadGuard,
|
|||
timer: Timer::new(),
|
||||
// FIXME Find the real QuirksMode information for this document
|
||||
quirks_mode: QuirksMode::NoQuirks,
|
||||
animation_only_restyle: animation_only,
|
||||
}
|
||||
}
|
||||
|
||||
fn traverse_subtree(element: GeckoElement, raw_data: RawServoStyleSetBorrowed,
|
||||
unstyled_children_only: bool) {
|
||||
traversal_flags: TraversalFlags) {
|
||||
// When new content is inserted in a display:none subtree, we will call into
|
||||
// servo to try to style it. Detect that here and bail out.
|
||||
if let Some(parent) = element.parent_element() {
|
||||
|
@ -155,7 +158,7 @@ fn traverse_subtree(element: GeckoElement, raw_data: RawServoStyleSetBorrowed,
|
|||
|
||||
let per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
|
||||
|
||||
let token = RecalcStyleOnly::pre_traverse(element, &per_doc_data.stylist, unstyled_children_only);
|
||||
let token = RecalcStyleOnly::pre_traverse(element, &per_doc_data.stylist, traversal_flags);
|
||||
if !token.should_traverse() {
|
||||
return;
|
||||
}
|
||||
|
@ -165,7 +168,8 @@ fn traverse_subtree(element: GeckoElement, raw_data: RawServoStyleSetBorrowed,
|
|||
|
||||
let global_style_data = &*GLOBAL_STYLE_DATA;
|
||||
let guard = global_style_data.shared_lock.read();
|
||||
let shared_style_context = create_shared_context(&guard, &per_doc_data);
|
||||
let shared_style_context = create_shared_context(&guard, &per_doc_data,
|
||||
traversal_flags.for_animation_only());
|
||||
|
||||
let traversal_driver = if global_style_data.style_thread_pool.is_none() {
|
||||
TraversalDriver::Sequential
|
||||
|
@ -192,8 +196,18 @@ pub extern "C" fn Servo_TraverseSubtree(root: RawGeckoElementBorrowed,
|
|||
behavior: structs::TraversalRootBehavior) -> bool {
|
||||
let element = GeckoElement(root);
|
||||
debug!("Servo_TraverseSubtree: {:?}", element);
|
||||
traverse_subtree(element, raw_data,
|
||||
behavior == structs::TraversalRootBehavior::UnstyledChildrenOnly);
|
||||
|
||||
let traversal_flags = match behavior {
|
||||
structs::TraversalRootBehavior::UnstyledChildrenOnly => UNSTYLED_CHILDREN_ONLY,
|
||||
_ => TraversalFlags::empty(),
|
||||
};
|
||||
|
||||
if element.has_animation_only_dirty_descendants() ||
|
||||
element.has_animation_restyle_hints() {
|
||||
traverse_subtree(element, raw_data, traversal_flags | ANIMATION_ONLY);
|
||||
}
|
||||
|
||||
traverse_subtree(element, raw_data, traversal_flags);
|
||||
|
||||
element.has_dirty_descendants() || element.mutate_data().unwrap().has_restyle()
|
||||
}
|
||||
|
@ -1359,7 +1373,9 @@ pub extern "C" fn Servo_CSSSupports(cond: *const nsACString) -> bool {
|
|||
|
||||
/// Only safe to call on the main thread, with exclusive access to the element and
|
||||
/// its ancestors.
|
||||
unsafe fn maybe_restyle<'a>(data: &'a mut AtomicRefMut<ElementData>, element: GeckoElement)
|
||||
unsafe fn maybe_restyle<'a>(data: &'a mut AtomicRefMut<ElementData>,
|
||||
element: GeckoElement,
|
||||
animation_only: bool)
|
||||
-> Option<&'a mut RestyleData>
|
||||
{
|
||||
// Don't generate a useless RestyleData if the element hasn't been styled.
|
||||
|
@ -1371,8 +1387,13 @@ unsafe fn maybe_restyle<'a>(data: &'a mut AtomicRefMut<ElementData>, element: Ge
|
|||
let mut curr = element;
|
||||
while let Some(parent) = curr.parent_element() {
|
||||
curr = parent;
|
||||
if curr.has_dirty_descendants() { break; }
|
||||
curr.set_dirty_descendants();
|
||||
if animation_only {
|
||||
if curr.has_animation_only_dirty_descendants() { break; }
|
||||
curr.set_animation_only_dirty_descendants();
|
||||
} else {
|
||||
if curr.has_dirty_descendants() { break; }
|
||||
curr.set_dirty_descendants();
|
||||
}
|
||||
}
|
||||
bindings::Gecko_SetOwnerDocumentNeedsStyleFlush(element.0);
|
||||
|
||||
|
@ -1387,7 +1408,7 @@ pub extern "C" fn Servo_Element_GetSnapshot(element: RawGeckoElementBorrowed) ->
|
|||
let snapshot = match element.mutate_data() {
|
||||
None => ptr::null_mut(),
|
||||
Some(mut data) => {
|
||||
if let Some(restyle_data) = unsafe { maybe_restyle(&mut data, element) } {
|
||||
if let Some(restyle_data) = unsafe { maybe_restyle(&mut data, element, false) } {
|
||||
restyle_data.snapshot.ensure(|| element.create_snapshot()).borrow_mut_raw()
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
|
@ -1407,10 +1428,14 @@ pub extern "C" fn Servo_NoteExplicitHints(element: RawGeckoElementBorrowed,
|
|||
let damage = GeckoRestyleDamage::new(change_hint);
|
||||
debug!("Servo_NoteExplicitHints: {:?}, restyle_hint={:?}, change_hint={:?}",
|
||||
element, restyle_hint, change_hint);
|
||||
debug_assert!(restyle_hint == structs::nsRestyleHint_eRestyle_CSSAnimations ||
|
||||
(restyle_hint.0 & structs::nsRestyleHint_eRestyle_CSSAnimations.0) == 0,
|
||||
"eRestyle_CSSAnimations should only appear by itself");
|
||||
|
||||
let mut maybe_data = element.mutate_data();
|
||||
let maybe_restyle_data =
|
||||
maybe_data.as_mut().and_then(|d| unsafe { maybe_restyle(d, element) });
|
||||
let maybe_restyle_data = maybe_data.as_mut().and_then(|d| unsafe {
|
||||
maybe_restyle(d, element, restyle_hint == structs::nsRestyleHint_eRestyle_CSSAnimations)
|
||||
});
|
||||
if let Some(restyle_data) = maybe_restyle_data {
|
||||
let restyle_hint: RestyleHint = restyle_hint.into();
|
||||
restyle_data.hint.insert(&restyle_hint.into());
|
||||
|
@ -1492,7 +1517,7 @@ pub extern "C" fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
|
|||
}
|
||||
|
||||
// We don't have the style ready. Go ahead and compute it as necessary.
|
||||
let shared = create_shared_context(&guard, &mut doc_data.borrow_mut());
|
||||
let shared = create_shared_context(&guard, &mut doc_data.borrow_mut(), false);
|
||||
let mut tlc = ThreadLocalStyleContext::new(&shared);
|
||||
let mut context = StyleContext {
|
||||
shared: &shared,
|
||||
|
@ -1592,7 +1617,7 @@ pub extern "C" fn Servo_AssertTreeIsClean(root: RawGeckoElementBorrowed) {
|
|||
|
||||
let root = GeckoElement(root);
|
||||
fn assert_subtree_is_clean<'le>(el: GeckoElement<'le>) {
|
||||
debug_assert!(!el.has_dirty_descendants());
|
||||
debug_assert!(!el.has_dirty_descendants() && !el.has_animation_only_dirty_descendants());
|
||||
for child in el.as_node().children() {
|
||||
if let Some(child) = child.as_element() {
|
||||
assert_subtree_is_clean(child);
|
||||
|
|
|
@ -1 +1 @@
|
|||
8c72b7651f231f589bc81d78fb9602d5a0899213
|
||||
7dd4e2db785c8ec360a989f69891b1e97dd4d369
|
||||
|
|
|
@ -151,11 +151,11 @@ fn test_replace_hosts() {
|
|||
host_table.insert("servo.test.server".to_owned(), ip("127.0.0.2"));
|
||||
|
||||
let url = ServoUrl::parse("http://foo.bar.com:8000/foo").unwrap();
|
||||
assert_eq!(host_replacement(&host_table, &url).host_str().unwrap(), "127.0.0.1");
|
||||
assert_eq!(host_replacement(&host_table, url).host_str().unwrap(), "127.0.0.1");
|
||||
|
||||
let url = ServoUrl::parse("http://servo.test.server").unwrap();
|
||||
assert_eq!(host_replacement(&host_table, &url).host_str().unwrap(), "127.0.0.2");
|
||||
assert_eq!(host_replacement(&host_table, url).host_str().unwrap(), "127.0.0.2");
|
||||
|
||||
let url = ServoUrl::parse("http://a.foo.bar.com").unwrap();
|
||||
assert_eq!(host_replacement(&host_table, &url).host_str().unwrap(), "a.foo.bar.com");
|
||||
assert_eq!(host_replacement(&host_table, url).host_str().unwrap(), "a.foo.bar.com");
|
||||
}
|
||||
|
|
|
@ -1170,4 +1170,30 @@ mod shorthand_serialization {
|
|||
assert_eq!(shadow.to_css_string(), shadow_css);
|
||||
}
|
||||
}
|
||||
|
||||
mod counter_increment {
|
||||
pub use super::*;
|
||||
pub use style::properties::longhands::counter_increment::SpecifiedValue as CounterIncrement;
|
||||
|
||||
#[test]
|
||||
fn counter_increment_with_properties_should_serialize_correctly() {
|
||||
let mut properties = Vec::new();
|
||||
|
||||
properties.push(("counter1".to_owned(), 1));
|
||||
properties.push(("counter2".to_owned(), -4));
|
||||
|
||||
let counter_increment = CounterIncrement(properties);
|
||||
let counter_increment_css = "counter1 1 counter2 -4";
|
||||
|
||||
assert_eq!(counter_increment.to_css_string(), counter_increment_css);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn counter_increment_without_properties_should_serialize_correctly() {
|
||||
let counter_increment = CounterIncrement(Vec::new());
|
||||
let counter_increment_css = "none";
|
||||
|
||||
assert_eq!(counter_increment.to_css_string(), counter_increment_css);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ class GeckoInstance(object):
|
|||
"hangmonitor.timeout": 0,
|
||||
|
||||
"javascript.options.showInConsole": True,
|
||||
"marionette.defaultPrefs.enabled": True,
|
||||
"marionette.enabled": True,
|
||||
"media.volume_scale": "0.01",
|
||||
|
||||
# Make sure the disk cache doesn't get auto disabled
|
||||
|
|
|
@ -36,7 +36,10 @@ class Timeouts(object):
|
|||
self._marionette._send_message("timeouts", {"type": name, "ms": ms})
|
||||
|
||||
def _get(self, name):
|
||||
ms = self._marionette._send_message("getTimeouts", key=name)
|
||||
ts = self._marionette._send_message("getTimeouts")
|
||||
if name not in ts:
|
||||
raise KeyError()
|
||||
ms = ts[name]
|
||||
return ms / 1000
|
||||
|
||||
@property
|
||||
|
@ -63,7 +66,11 @@ class Timeouts(object):
|
|||
minutes (or 300 seconds).
|
||||
|
||||
"""
|
||||
return self._get("page load")
|
||||
# remove fallback when Firefox 56 is stable
|
||||
try:
|
||||
return self._get("pageLoad")
|
||||
except KeyError:
|
||||
return self._get("page load")
|
||||
|
||||
@page_load.setter
|
||||
def page_load(self, sec):
|
||||
|
@ -71,7 +78,11 @@ class Timeouts(object):
|
|||
to wait for the page loading to complete.
|
||||
|
||||
"""
|
||||
self._set("page load", sec)
|
||||
# remove fallback when Firefox 56 is stable
|
||||
try:
|
||||
self._set("pageLoad", sec)
|
||||
except errors.InvalidArgumentException:
|
||||
return self._set("page load", sec)
|
||||
|
||||
@property
|
||||
def implicit(self):
|
||||
|
|
|
@ -6,80 +6,76 @@
|
|||
|
||||
const {Constructor: CC, interfaces: Ci, utils: Cu, classes: Cc} = Components;
|
||||
|
||||
const MARIONETTE_CONTRACTID = "@mozilla.org/marionette;1";
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const MARIONETTE_CONTRACT_ID = "@mozilla.org/marionette;1";
|
||||
const MARIONETTE_CID = Components.ID("{786a1369-dca5-4adc-8486-33d23c88010a}");
|
||||
|
||||
const DEFAULT_PORT = 2828;
|
||||
const ENABLED_PREF = "marionette.defaultPrefs.enabled";
|
||||
const PORT_PREF = "marionette.defaultPrefs.port";
|
||||
const FORCELOCAL_PREF = "marionette.force-local";
|
||||
const LOG_PREF = "marionette.logging";
|
||||
const PREF_ENABLED = "marionette.enabled";
|
||||
const PREF_ENABLED_FALLBACK = "marionette.defaultPrefs.enabled";
|
||||
const PREF_PORT = "marionette.port";
|
||||
const PREF_PORT_FALLBACK = "marionette.defaultPrefs.port";
|
||||
const PREF_LOG_LEVEL = "marionette.log.level";
|
||||
const PREF_LOG_LEVEL_FALLBACK = "marionette.logging";
|
||||
const PREF_FORCE_LOCAL = "marionette.forcelocal";
|
||||
const PREF_FORCE_LOCAL_FALLBACK = "marionette.force-local";
|
||||
|
||||
/**
|
||||
* Besides starting based on existing prefs in a profile and a commandline flag,
|
||||
* we also support inheriting prefs out of an env var, and to start marionette
|
||||
* that way.
|
||||
* This allows marionette prefs to persist when we do a restart into a
|
||||
* different profile in order to test things like Firefox refresh.
|
||||
* The env var itself, if present, is interpreted as a JSON structure, with the
|
||||
* keys mapping to preference names in the "marionette." branch, and the values
|
||||
* to the values of those prefs. So something like {"defaultPrefs.enabled": true}
|
||||
* in the env var would result in the marionette.defaultPrefs.enabled pref being
|
||||
* set to true, thus triggering marionette being enabled for that startup.
|
||||
*/
|
||||
const DEFAULT_PORT = 2828;
|
||||
const DEFAULT_LOG_LEVEL = "info";
|
||||
const LOG_LEVELS = new Map([
|
||||
["fatal", Log.Level.Fatal],
|
||||
["error", Log.Level.Error],
|
||||
["warn", Log.Level.Warn],
|
||||
["info", Log.Level.Info],
|
||||
["config", Log.Level.Config],
|
||||
["debug", Log.Level.Debug],
|
||||
["trace", Log.Level.Trace],
|
||||
]);
|
||||
|
||||
// Besides starting based on existing prefs in a profile and a command
|
||||
// line flag, we also support inheriting prefs out of an env var, and to
|
||||
// start Marionette that way.
|
||||
//
|
||||
// This allows marionette prefs to persist when we do a restart into
|
||||
// a different profile in order to test things like Firefox refresh.
|
||||
// The environment variable itself, if present, is interpreted as a
|
||||
// JSON structure, with the keys mapping to preference names in the
|
||||
// "marionette." branch, and the values to the values of those prefs. So
|
||||
// something like {"enabled": true} would result in the marionette.enabled
|
||||
// pref being set to true, thus triggering marionette being enabled for
|
||||
// that startup.
|
||||
const ENV_PREF_VAR = "MOZ_MARIONETTE_PREF_STATE_ACROSS_RESTARTS";
|
||||
|
||||
const ServerSocket = CC("@mozilla.org/network/server-socket;1",
|
||||
"nsIServerSocket",
|
||||
"initSpecialConnection");
|
||||
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
// Marionette preferences recently changed names. This is an abstraction
|
||||
// that first looks for the new name, but falls back to using the old name
|
||||
// if the new does not exist.
|
||||
//
|
||||
// This shim can be removed when Firefox 55 ships.
|
||||
const prefs = {
|
||||
get port () {
|
||||
let fallback = Preferences.get(PREF_PORT_FALLBACK, DEFAULT_PORT);
|
||||
return Preferences.get(PREF_PORT, fallback);
|
||||
},
|
||||
|
||||
function MarionetteComponent() {
|
||||
this.loaded_ = false;
|
||||
this.observerService = Services.obs;
|
||||
this.logger = this.setupLogger_(this.determineLoggingLevel_());
|
||||
}
|
||||
|
||||
MarionetteComponent.prototype = {
|
||||
classDescription: "Marionette component",
|
||||
classID: MARIONETTE_CID,
|
||||
contractID: MARIONETTE_CONTRACTID,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler, Ci.nsIObserver]),
|
||||
_xpcom_categories: [
|
||||
{category: "command-line-handler", entry: "b-marionette"},
|
||||
{category: "profile-after-change", service: true}
|
||||
],
|
||||
enabled: false,
|
||||
finalUiStartup: false,
|
||||
gfxWindow: null,
|
||||
server: null,
|
||||
};
|
||||
|
||||
MarionetteComponent.prototype.setupLogger_ = function (level) {
|
||||
let log = Log.repository.getLogger("Marionette");
|
||||
log.level = level;
|
||||
log.addAppender(new Log.DumpAppender());
|
||||
return log;
|
||||
};
|
||||
|
||||
MarionetteComponent.prototype.determineLoggingLevel_ = function() {
|
||||
let level = Log.Level.Info;
|
||||
|
||||
// marionette.logging pref can override default
|
||||
// with an entry from the Log.Level enum
|
||||
if (Preferences.has(LOG_PREF)) {
|
||||
let p = Preferences.get(LOG_PREF);
|
||||
get logLevel () {
|
||||
let level = DEFAULT_LOG_LEVEL;
|
||||
let fallback = Preferences.get(PREF_LOG_LEVEL_FALLBACK, level);
|
||||
let p = Preferences.get(PREF_LOG_LEVEL, fallback);
|
||||
|
||||
switch (typeof p) {
|
||||
// Gecko >= 46
|
||||
case "string":
|
||||
let s = p.toLowerCase();
|
||||
s = s.charAt(0).toUpperCase() + s.slice(1);
|
||||
level = Log.Level[s];
|
||||
if (LOG_LEVELS.has(s)) {
|
||||
level = LOG_LEVELS.get(s);
|
||||
}
|
||||
break;
|
||||
|
||||
// Gecko <= 45
|
||||
|
@ -89,13 +85,81 @@ MarionetteComponent.prototype.determineLoggingLevel_ = function() {
|
|||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return level;
|
||||
return level;
|
||||
},
|
||||
|
||||
get forceLocal () {
|
||||
let fallback = Preferences.get(PREF_FORCE_LOCAL_FALLBACK, true);
|
||||
return Preferences.get(PREF_FORCE_LOCAL, fallback);
|
||||
},
|
||||
|
||||
readFromEnvironment (key) {
|
||||
const env = Cc["@mozilla.org/process/environment;1"]
|
||||
.getService(Ci.nsIEnvironment);
|
||||
|
||||
if (env.exists(key)) {
|
||||
let prefs;
|
||||
try {
|
||||
prefs = JSON.parse(env.get(key));
|
||||
} catch (e) {
|
||||
Cu.reportError(
|
||||
"Invalid Marionette preferences in environment; " +
|
||||
"preferences will not have been applied");
|
||||
Cu.reportError(e);
|
||||
}
|
||||
|
||||
if (prefs) {
|
||||
for (let prefName of Object.keys(prefs)) {
|
||||
Preferences.set("marionette." + prefName, prefs[prefName]);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
MarionetteComponent.prototype.onSocketAccepted = function(
|
||||
socket, transport) {
|
||||
function MarionetteComponent() {
|
||||
// guards against this component
|
||||
// being initialised multiple times
|
||||
this.running = false;
|
||||
|
||||
// holds a reference to server.TCPListener
|
||||
this.server = null;
|
||||
|
||||
// holds reference to ChromeWindow
|
||||
// used to run GFX sanity tests on Windows
|
||||
this.gfxWindow = null;
|
||||
|
||||
// indicates that all pending window checks have been completed
|
||||
// and that we are ready to start the Marionette server
|
||||
this.finalUIStartup = false;
|
||||
|
||||
this.logger = this.setupLogger(prefs.logLevel);
|
||||
Services.prefs.addObserver(PREF_ENABLED, this, false);
|
||||
|
||||
if (Preferences.isSet(PREF_ENABLED_FALLBACK)) {
|
||||
this.logger.warn(`Deprecated preference ${PREF_ENABLED_FALLBACK} detected, ` +
|
||||
`please use ${PREF_ENABLED}`);
|
||||
Preferences.set(PREF_ENABLED, Preferences.get(PREF_ENABLED_FALLBACK));
|
||||
}
|
||||
}
|
||||
|
||||
MarionetteComponent.prototype = {
|
||||
classDescription: "Marionette component",
|
||||
classID: MARIONETTE_CID,
|
||||
contractID: MARIONETTE_CONTRACT_ID,
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsICommandLineHandler,
|
||||
Ci.nsIObserver,
|
||||
]),
|
||||
_xpcom_categories: [
|
||||
{category: "command-line-handler", entry: "b-marionette"},
|
||||
{category: "profile-after-change", service: true},
|
||||
],
|
||||
helpInfo: " --marionette Enable remote control server.\n",
|
||||
};
|
||||
|
||||
MarionetteComponent.prototype.onSocketAccepted = function (socket, transport) {
|
||||
this.logger.info("onSocketAccepted for Marionette dummy socket");
|
||||
};
|
||||
|
||||
|
@ -104,59 +168,70 @@ MarionetteComponent.prototype.onStopListening = function (socket, status) {
|
|||
socket.close();
|
||||
};
|
||||
|
||||
/** Check cmdLine argument for {@code --marionette}. */
|
||||
// Handle --marionette flag
|
||||
MarionetteComponent.prototype.handle = function (cmdLine) {
|
||||
// if the CLI is there then lets do work otherwise nothing to see
|
||||
if (cmdLine.handleFlag("marionette", false)) {
|
||||
this.enabled = true;
|
||||
this.logger.debug("Marionette enabled via command-line flag");
|
||||
this.init();
|
||||
}
|
||||
};
|
||||
|
||||
Object.defineProperty(MarionetteComponent.prototype, "enabled", {
|
||||
set (value) {
|
||||
Preferences.set(PREF_ENABLED, value);
|
||||
},
|
||||
|
||||
get () {
|
||||
return Preferences.get(PREF_ENABLED);
|
||||
},
|
||||
});
|
||||
|
||||
MarionetteComponent.prototype.observe = function (subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "nsPref:changed":
|
||||
if (Preferences.get(PREF_ENABLED)) {
|
||||
this.init();
|
||||
} else {
|
||||
this.uninit();
|
||||
}
|
||||
break;
|
||||
|
||||
case "profile-after-change":
|
||||
// Using sessionstore-windows-restored as the xpcom category doesn't seem to work,
|
||||
// so we wait for that by adding an observer here.
|
||||
this.observerService.addObserver(this, "sessionstore-windows-restored", false);
|
||||
// Using sessionstore-windows-restored as the xpcom category doesn't
|
||||
// seem to work, so we wait for that by adding an observer here.
|
||||
Services.obs.addObserver(this, "sessionstore-windows-restored", false);
|
||||
|
||||
this.maybeReadPrefsFromEnvironment();
|
||||
prefs.readFromEnvironment(ENV_PREF_VAR);
|
||||
|
||||
#ifdef ENABLE_MARIONETTE
|
||||
this.enabled = Preferences.get(ENABLED_PREF, false);
|
||||
if (this.enabled) {
|
||||
this.logger.debug("Marionette enabled via build flag and pref");
|
||||
|
||||
// We want to suppress the modal dialog that's shown
|
||||
// when starting up in safe-mode to enable testing.
|
||||
if (Services.appinfo.inSafeMode) {
|
||||
this.observerService.addObserver(this, "domwindowopened", false);
|
||||
Services.obs.addObserver(this, "domwindowopened", false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case "domwindowclosed":
|
||||
if (this.gfxWindow === null || subject === this.gfxWindow) {
|
||||
this.observerService.removeObserver(this, topic);
|
||||
Services.obs.removeObserver(this, topic);
|
||||
|
||||
this.observerService.addObserver(this, "xpcom-shutdown", false);
|
||||
this.finalUiStartup = true;
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
this.finalUIStartup = true;
|
||||
this.init();
|
||||
}
|
||||
break;
|
||||
|
||||
case "domwindowopened":
|
||||
this.observerService.removeObserver(this, topic);
|
||||
this.suppressSafeModeDialog_(subj);
|
||||
Services.obs.removeObserver(this, topic);
|
||||
this.suppressSafeModeDialog(subject);
|
||||
break;
|
||||
|
||||
case "sessionstore-windows-restored":
|
||||
this.observerService.removeObserver(this, topic);
|
||||
Services.obs.removeObserver(this, topic);
|
||||
|
||||
// When Firefox starts on Windows, an additional GFX sanity test window
|
||||
// may appear off-screen. Marionette should wait for it to close.
|
||||
// When Firefox starts on Windows, an additional GFX sanity test
|
||||
// window may appear off-screen. Marionette should wait for it
|
||||
// to close.
|
||||
let winEn = Services.wm.getEnumerator(null);
|
||||
while (winEn.hasMoreElements()) {
|
||||
let win = winEn.getNext();
|
||||
|
@ -167,46 +242,33 @@ MarionetteComponent.prototype.observe = function (subject, topic, data) {
|
|||
}
|
||||
|
||||
if (this.gfxWindow) {
|
||||
this.observerService.addObserver(this, "domwindowclosed", false);
|
||||
Services.obs.addObserver(this, "domwindowclosed", false);
|
||||
} else {
|
||||
this.observerService.addObserver(this, "xpcom-shutdown", false);
|
||||
this.finalUiStartup = true;
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
this.finalUIStartup = true;
|
||||
this.init();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "xpcom-shutdown":
|
||||
this.observerService.removeObserver(this, "xpcom-shutdown");
|
||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
||||
this.uninit();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
MarionetteComponent.prototype.maybeReadPrefsFromEnvironment = function() {
|
||||
let env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
|
||||
if (env.exists(ENV_PREF_VAR)) {
|
||||
let prefStr = env.get(ENV_PREF_VAR);
|
||||
let prefs;
|
||||
try {
|
||||
prefs = JSON.parse(prefStr);
|
||||
} catch (ex) {
|
||||
Cu.reportError("Invalid marionette prefs in environment; prefs won't have been applied.");
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
if (prefs) {
|
||||
for (let prefName of Object.keys(prefs)) {
|
||||
Preferences.set("marionette." + prefName, prefs[prefName]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MarionetteComponent.prototype.setupLogger = function (level) {
|
||||
let logger = Log.repository.getLogger("Marionette");
|
||||
logger.level = level;
|
||||
logger.addAppender(new Log.DumpAppender());
|
||||
return logger;
|
||||
};
|
||||
|
||||
MarionetteComponent.prototype.suppressSafeModeDialog_ = function (win) {
|
||||
// Wait for the modal dialog to finish loading.
|
||||
win.addEventListener("load", function() {
|
||||
MarionetteComponent.prototype.suppressSafeModeDialog = function (win) {
|
||||
win.addEventListener("load", () => {
|
||||
if (win.document.getElementById("safeModeDialog")) {
|
||||
// Accept the dialog to start in safe-mode
|
||||
// accept the dialog to start in safe-mode
|
||||
win.setTimeout(() => {
|
||||
win.document.documentElement.getButton("accept").click();
|
||||
});
|
||||
|
@ -214,18 +276,12 @@ MarionetteComponent.prototype.suppressSafeModeDialog_ = function (win) {
|
|||
}, {once: true});
|
||||
};
|
||||
|
||||
MarionetteComponent.prototype.init = function() {
|
||||
if (this.loaded_ || !this.enabled || !this.finalUiStartup) {
|
||||
MarionetteComponent.prototype.init = function () {
|
||||
if (this.running || !this.enabled || !this.finalUIStartup) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.loaded_ = true;
|
||||
|
||||
let forceLocal = Preferences.get(FORCELOCAL_PREF,
|
||||
Services.appinfo.name == "B2G" ? false : true);
|
||||
Preferences.set(FORCELOCAL_PREF, forceLocal);
|
||||
|
||||
if (!forceLocal) {
|
||||
if (!prefs.forceLocal) {
|
||||
// See bug 800138. Because the first socket that opens with
|
||||
// force-local=false fails, we open a dummy socket that will fail.
|
||||
// keepWhenOffline=true so that it still work when offline (local).
|
||||
|
@ -236,30 +292,30 @@ MarionetteComponent.prototype.init = function() {
|
|||
insaneSacrificialGoat.asyncListen(this);
|
||||
}
|
||||
|
||||
let port = Preferences.get(PORT_PREF, DEFAULT_PORT);
|
||||
|
||||
let s;
|
||||
try {
|
||||
Cu.import("chrome://marionette/content/server.js");
|
||||
s = new MarionetteServer(port, forceLocal);
|
||||
s = new server.TCPListener(prefs.port, prefs.forceLocal);
|
||||
s.start();
|
||||
this.logger.info(`Listening on port ${s.port}`);
|
||||
} catch (e) {
|
||||
this.logger.error(`Error on starting server: ${e}`);
|
||||
dump(e.toString() + "\n" + e.stack + "\n");
|
||||
dump(`${e.toString()}\n${e.stack}\n`);
|
||||
} finally {
|
||||
if (s) {
|
||||
this.server = s;
|
||||
this.running = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MarionetteComponent.prototype.uninit = function() {
|
||||
if (!this.loaded_) {
|
||||
MarionetteComponent.prototype.uninit = function () {
|
||||
if (!this.running) {
|
||||
return;
|
||||
}
|
||||
this.server.stop();
|
||||
this.loaded_ = false;
|
||||
this.logger.info("Ceased listening");
|
||||
this.running = false;
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([MarionetteComponent]);
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
# 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/.
|
||||
|
||||
EXTRA_COMPONENTS += ["marionette.manifest"]
|
||||
EXTRA_PP_COMPONENTS += ["marionette.js"]
|
||||
|
||||
if CONFIG["ENABLE_MARIONETTE"]:
|
||||
DEFINES["ENABLE_MARIONETTE"] = 1
|
||||
EXTRA_COMPONENTS += [
|
||||
"marionette.js",
|
||||
"marionette.manifest",
|
||||
]
|
||||
|
|
|
@ -1,228 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
Cu.import("chrome://marionette/content/assert.js");
|
||||
Cu.import("chrome://marionette/content/driver.js");
|
||||
Cu.import("chrome://marionette/content/error.js");
|
||||
Cu.import("chrome://marionette/content/message.js");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["Dispatcher"];
|
||||
|
||||
const PROTOCOL_VERSION = 3;
|
||||
|
||||
const logger = Log.repository.getLogger("Marionette");
|
||||
|
||||
/**
|
||||
* Manages a Marionette connection, and dispatches packets received to
|
||||
* their correct destinations.
|
||||
*
|
||||
* @param {number} connId
|
||||
* Unique identifier of the connection this dispatcher should handle.
|
||||
* @param {DebuggerTransport} transport
|
||||
* Debugger transport connection to the client.
|
||||
* @param {function(): GeckoDriver} driverFactory
|
||||
* A factory function that produces a GeckoDriver.
|
||||
*/
|
||||
this.Dispatcher = function (connId, transport, driverFactory) {
|
||||
this.connId = connId;
|
||||
this.conn = transport;
|
||||
|
||||
// transport hooks are Dispatcher#onPacket
|
||||
// and Dispatcher#onClosed
|
||||
this.conn.hooks = this;
|
||||
|
||||
// callback for when connection is closed
|
||||
this.onclose = null;
|
||||
|
||||
// last received/sent message ID
|
||||
this.lastId = 0;
|
||||
|
||||
this.driver = driverFactory();
|
||||
|
||||
// lookup of commands sent by server to client by message ID
|
||||
this.commands_ = new Map();
|
||||
};
|
||||
|
||||
/**
|
||||
* Debugger transport callback that cleans up
|
||||
* after a connection is closed.
|
||||
*/
|
||||
Dispatcher.prototype.onClosed = function (reason) {
|
||||
this.driver.deleteSession();
|
||||
if (this.onclose) {
|
||||
this.onclose(this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback that receives data packets from the client.
|
||||
*
|
||||
* If the message is a Response, we look up the command previously issued
|
||||
* to the client and run its callback, if any. In case of a Command,
|
||||
* the corresponding is executed.
|
||||
*
|
||||
* @param {Array.<number, number, ?, ?>} data
|
||||
* A four element array where the elements, in sequence, signifies
|
||||
* message type, message ID, method name or error, and parameters
|
||||
* or result.
|
||||
*/
|
||||
Dispatcher.prototype.onPacket = function (data) {
|
||||
let msg = Message.fromMsg(data);
|
||||
msg.origin = MessageOrigin.Client;
|
||||
this.log_(msg);
|
||||
|
||||
if (msg instanceof Response) {
|
||||
let cmd = this.commands_.get(msg.id);
|
||||
this.commands_.delete(msg.id);
|
||||
cmd.onresponse(msg);
|
||||
} else if (msg instanceof Command) {
|
||||
this.lastId = msg.id;
|
||||
this.execute(msg);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Executes a WebDriver command and sends back a response when it has
|
||||
* finished executing.
|
||||
*
|
||||
* Commands implemented in GeckoDriver and registered in its
|
||||
* {@code GeckoDriver.commands} attribute. The return values from
|
||||
* commands are expected to be Promises. If the resolved value of said
|
||||
* promise is not an object, the response body will be wrapped in an object
|
||||
* under a "value" field.
|
||||
*
|
||||
* If the command implementation sends the response itself by calling
|
||||
* {@code resp.send()}, the response is guaranteed to not be sent twice.
|
||||
*
|
||||
* Errors thrown in commands are marshaled and sent back, and if they
|
||||
* are not WebDriverError instances, they are additionally propagated and
|
||||
* reported to {@code Components.utils.reportError}.
|
||||
*
|
||||
* @param {Command} cmd
|
||||
* The requested command to execute.
|
||||
*/
|
||||
Dispatcher.prototype.execute = function (cmd) {
|
||||
let resp = new Response(cmd.id, this.send.bind(this));
|
||||
let sendResponse = () => resp.sendConditionally(resp => !resp.sent);
|
||||
let sendError = resp.sendError.bind(resp);
|
||||
|
||||
let req = Task.spawn(function*() {
|
||||
let fn = this.driver.commands[cmd.name];
|
||||
if (typeof fn == "undefined") {
|
||||
throw new UnknownCommandError(cmd.name);
|
||||
}
|
||||
|
||||
if (cmd.name !== "newSession") {
|
||||
assert.session(this.driver);
|
||||
}
|
||||
|
||||
let rv = yield fn.bind(this.driver)(cmd, resp);
|
||||
|
||||
if (typeof rv != "undefined") {
|
||||
if (typeof rv != "object") {
|
||||
resp.body = {value: rv};
|
||||
} else {
|
||||
resp.body = rv;
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
req.then(sendResponse, sendError).catch(error.report);
|
||||
};
|
||||
|
||||
Dispatcher.prototype.sendError = function (err, cmdId) {
|
||||
let resp = new Response(cmdId, this.send.bind(this));
|
||||
resp.sendError(err);
|
||||
};
|
||||
|
||||
// Convenience methods:
|
||||
|
||||
/**
|
||||
* When a client connects we send across a JSON Object defining the
|
||||
* protocol level.
|
||||
*
|
||||
* This is the only message sent by Marionette that does not follow
|
||||
* the regular message format.
|
||||
*/
|
||||
Dispatcher.prototype.sayHello = function() {
|
||||
let whatHo = {
|
||||
applicationType: "gecko",
|
||||
marionetteProtocol: PROTOCOL_VERSION,
|
||||
};
|
||||
this.sendRaw(whatHo);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Delegates message to client based on the provided {@code cmdId}.
|
||||
* The message is sent over the debugger transport socket.
|
||||
*
|
||||
* The command ID is a unique identifier assigned to the client's request
|
||||
* that is used to distinguish the asynchronous responses.
|
||||
*
|
||||
* Whilst responses to commands are synchronous and must be sent in the
|
||||
* correct order.
|
||||
*
|
||||
* @param {Command,Response} msg
|
||||
* The command or response to send.
|
||||
*/
|
||||
Dispatcher.prototype.send = function (msg) {
|
||||
msg.origin = MessageOrigin.Server;
|
||||
if (msg instanceof Command) {
|
||||
this.commands_.set(msg.id, msg);
|
||||
this.sendToEmulator(msg);
|
||||
} else if (msg instanceof Response) {
|
||||
this.sendToClient(msg);
|
||||
}
|
||||
};
|
||||
|
||||
// Low-level methods:
|
||||
|
||||
/**
|
||||
* Send given response to the client over the debugger transport socket.
|
||||
*
|
||||
* @param {Response} resp
|
||||
* The response to send back to the client.
|
||||
*/
|
||||
Dispatcher.prototype.sendToClient = function (resp) {
|
||||
this.driver.responseCompleted();
|
||||
this.sendMessage(resp);
|
||||
};
|
||||
|
||||
/**
|
||||
* Marshal message to the Marionette message format and send it.
|
||||
*
|
||||
* @param {Command,Response} msg
|
||||
* The message to send.
|
||||
*/
|
||||
Dispatcher.prototype.sendMessage = function (msg) {
|
||||
this.log_(msg);
|
||||
let payload = msg.toMsg();
|
||||
this.sendRaw(payload);
|
||||
};
|
||||
|
||||
/**
|
||||
* Send the given payload over the debugger transport socket to the
|
||||
* connected client.
|
||||
*
|
||||
* @param {Object} payload
|
||||
* The payload to ship.
|
||||
*/
|
||||
Dispatcher.prototype.sendRaw = function (payload) {
|
||||
this.conn.send(payload);
|
||||
};
|
||||
|
||||
Dispatcher.prototype.log_ = function (msg) {
|
||||
let a = (msg.origin == MessageOrigin.Client ? " -> " : " <- ");
|
||||
let s = JSON.stringify(msg.toMsg());
|
||||
logger.trace(this.connId + a + s);
|
||||
};
|
|
@ -35,7 +35,7 @@ class TestCapabilities(MarionetteTestCase):
|
|||
self.assertFalse(self.caps["acceptInsecureCerts"])
|
||||
self.assertDictEqual(self.caps["timeouts"],
|
||||
{"implicit": 0,
|
||||
"page load": 300000,
|
||||
"pageLoad": 300000,
|
||||
"script": 30000})
|
||||
|
||||
def test_supported_features(self):
|
||||
|
@ -245,7 +245,7 @@ class TestCapabilityMatching(MarionetteTestCase):
|
|||
self.assertEqual(self.marionette.get_pref("network.proxy.type"), 1)
|
||||
|
||||
def test_timeouts(self):
|
||||
timeouts = {u"implicit": 123, u"page load": 456, u"script": 789}
|
||||
timeouts = {u"implicit": 123, u"pageLoad": 456, u"script": 789}
|
||||
caps = {"desiredCapabilities": {"timeouts": timeouts}}
|
||||
self.marionette.start_session(caps)
|
||||
self.assertIn("timeouts", self.marionette.session_capabilities)
|
||||
|
|
|
@ -20,7 +20,6 @@ marionette.jar:
|
|||
content/error.js (error.js)
|
||||
content/wait.js (wait.js)
|
||||
content/message.js (message.js)
|
||||
content/dispatcher.js (dispatcher.js)
|
||||
content/modal.js (modal.js)
|
||||
content/proxy.js (proxy.js)
|
||||
content/capture.js (capture.js)
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
DIRS += ["components"]
|
||||
|
||||
JS_PREFERENCE_FILES += ["prefs.js"]
|
||||
|
||||
JAR_MANIFESTS += ["jar.mn"]
|
||||
MARIONETTE_UNIT_MANIFESTS += ["harness/marionette_harness/tests/unit/unit-tests.ini"]
|
||||
MARIONETTE_WEBAPI_MANIFESTS += ["harness/marionette_harness/tests/webapi-tests.ini"]
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/* 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/. */
|
||||
|
||||
// Whether or not Marionette is enabled.
|
||||
pref("marionette.enabled", false);
|
||||
|
||||
// Port to start Marionette server on.
|
||||
pref("marionette.port", 2828);
|
||||
|
||||
// Forces client connections to come from a loopback device.
|
||||
pref("marionette.forcelocal", true);
|
||||
|
||||
// Marionette logging verbosity. Allowed values are "fatal", "error",
|
||||
// "warn", "info", "config", "debug", and "trace".
|
||||
pref("marionette.log.level", "info");
|
||||
|
||||
// Sets preferences recommended when using Firefox in automation with
|
||||
// Marionette.
|
||||
pref("marionette.prefs.recommended", true);
|
|
@ -4,141 +4,585 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var {Constructor: CC, classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
const {Constructor: CC, classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader);
|
||||
const loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader);
|
||||
const ServerSocket = CC("@mozilla.org/network/server-socket;1", "nsIServerSocket", "initSpecialConnection");
|
||||
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
Cu.import("chrome://marionette/content/dispatcher.js");
|
||||
Cu.import("chrome://marionette/content/assert.js");
|
||||
Cu.import("chrome://marionette/content/driver.js");
|
||||
Cu.import("chrome://marionette/content/element.js");
|
||||
Cu.import("chrome://marionette/content/simpletest.js");
|
||||
Cu.import("chrome://marionette/content/error.js");
|
||||
Cu.import("chrome://marionette/content/message.js");
|
||||
|
||||
// Bug 1083711: Load transport.js as an SDK module instead of subscript
|
||||
loader.loadSubScript("resource://devtools/shared/transport/transport.js");
|
||||
|
||||
const logger = Log.repository.getLogger("Marionette");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["MarionetteServer"];
|
||||
this.EXPORTED_SYMBOLS = ["server"];
|
||||
this.server = {};
|
||||
|
||||
const CONTENT_LISTENER_PREF = "marionette.contentListener";
|
||||
const MANAGE_OFFLINE_STATUS_PREF = "network.gonk.manage-offline-status";
|
||||
const PROTOCOL_VERSION = 3;
|
||||
|
||||
const PREF_CONTENT_LISTENER = "marionette.contentListener";
|
||||
const PREF_RECOMMENDED = "marionette.prefs.recommended";
|
||||
|
||||
// Marionette sets preferences recommended for automation when it starts,
|
||||
// unless |marionette.prefs.recommended| has been set to false.
|
||||
// Where noted, some prefs should also be set in the profile passed to
|
||||
// Marionette to prevent them from affecting startup, since some of these
|
||||
// are checked before Marionette initialises.
|
||||
const RECOMMENDED_PREFS = new Map([
|
||||
|
||||
// Disable automatic downloading of new releases.
|
||||
//
|
||||
// This should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["app.update.auto", false],
|
||||
|
||||
// Disable automatically upgrading Firefox.
|
||||
//
|
||||
// This should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["app.update.enabled", false],
|
||||
|
||||
// Increase the APZ content response timeout in tests to 1 minute.
|
||||
// This is to accommodate the fact that test environments tends to be
|
||||
// slower than production environments (with the b2g emulator being
|
||||
// the slowest of them all), resulting in the production timeout value
|
||||
// sometimes being exceeded and causing false-positive test failures.
|
||||
//
|
||||
// (bug 1176798, bug 1177018, bug 1210465)
|
||||
["apz.content_response_timeout", 60000],
|
||||
|
||||
// Indicate that the download panel has been shown once so that
|
||||
// whichever download test runs first doesn't show the popup
|
||||
// inconsistently.
|
||||
["browser.download.panel.shown", true],
|
||||
|
||||
// Do not show the EULA notification.
|
||||
//
|
||||
// This should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["browser.EULA.override", true],
|
||||
|
||||
// Turn off about:newtab and make use of about:blank instead for new
|
||||
// opened tabs.
|
||||
//
|
||||
// This should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["browser.newtabpage.enabled", false],
|
||||
|
||||
// Assume the about:newtab page's intro panels have been shown to not
|
||||
// depend on which test runs first and happens to open about:newtab
|
||||
["browser.newtabpage.introShown", true],
|
||||
|
||||
// Never start the browser in offline mode
|
||||
//
|
||||
// This should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["browser.offline", false],
|
||||
|
||||
// Background thumbnails in particular cause grief, and disabling
|
||||
// thumbnails in general cannot hurt
|
||||
["browser.pagethumbnails.capturing_disabled", true],
|
||||
|
||||
// Avoid performing Reader Mode intros during tests
|
||||
["browser.reader.detectedFirstArticle", true],
|
||||
|
||||
// Disable safebrowsing components.
|
||||
//
|
||||
// These should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["browser.safebrowsing.blockedURIs.enabled", false],
|
||||
["browser.safebrowsing.downloads.enabled", false],
|
||||
["browser.safebrowsing.enabled", false],
|
||||
["browser.safebrowsing.forbiddenURIs.enabled", false],
|
||||
["browser.safebrowsing.malware.enabled", false],
|
||||
["browser.safebrowsing.phishing.enabled", false],
|
||||
|
||||
// Disable updates to search engines.
|
||||
//
|
||||
// Should be set in profile.
|
||||
["browser.search.update", false],
|
||||
|
||||
// Do not restore the last open set of tabs if the browser has crashed
|
||||
["browser.sessionstore.resume_from_crash", false],
|
||||
|
||||
// Don't check for the default web browser during startup.
|
||||
//
|
||||
// These should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["browser.shell.checkDefaultBrowser", false],
|
||||
|
||||
// Start with a blank page (about:blank)
|
||||
["browser.startup.page", 0],
|
||||
|
||||
// Disable tab animation
|
||||
["browser.tabs.animate", false],
|
||||
|
||||
// Do not allow background tabs to be zombified, otherwise for tests
|
||||
// that open additional tabs, the test harness tab itself might get
|
||||
// unloaded
|
||||
["browser.tabs.disableBackgroundZombification", false],
|
||||
|
||||
// Do not warn when closing all other open tabs
|
||||
["browser.tabs.warnOnCloseOtherTabs", false],
|
||||
|
||||
// Do not warn when multiple tabs will be opened
|
||||
["browser.tabs.warnOnOpen", false],
|
||||
|
||||
// Disable first run splash page on Windows 10
|
||||
["browser.usedOnWindows10.introURL", ""],
|
||||
|
||||
// Disable the UI tour.
|
||||
//
|
||||
// Should be set in profile.
|
||||
["browser.uitour.enabled", false],
|
||||
|
||||
// Do not show datareporting policy notifications which can
|
||||
// interfere with tests
|
||||
["datareporting.healthreport.about.reportUrl", "http://%(server)s/dummy/abouthealthreport/"],
|
||||
["datareporting.healthreport.documentServerURI", "http://%(server)s/dummy/healthreport/"],
|
||||
["datareporting.healthreport.logging.consoleEnabled", false],
|
||||
["datareporting.healthreport.service.enabled", false],
|
||||
["datareporting.healthreport.service.firstRun", false],
|
||||
["datareporting.healthreport.uploadEnabled", false],
|
||||
["datareporting.policy.dataSubmissionEnabled", false],
|
||||
["datareporting.policy.dataSubmissionPolicyAccepted", false],
|
||||
["datareporting.policy.dataSubmissionPolicyBypassNotification", true],
|
||||
|
||||
// Disable popup-blocker
|
||||
["dom.disable_open_during_load", false],
|
||||
|
||||
// Disable the ProcessHangMonitor
|
||||
["dom.ipc.reportProcessHangs", false],
|
||||
|
||||
// Disable slow script dialogues
|
||||
["dom.max_chrome_script_run_time", 0],
|
||||
["dom.max_script_run_time", 0],
|
||||
|
||||
// Only load extensions from the application and user profile
|
||||
// AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
|
||||
//
|
||||
// Should be set in profile.
|
||||
["extensions.autoDisableScopes", 0],
|
||||
["extensions.enabledScopes", 5],
|
||||
|
||||
// Do not block add-ons for e10s
|
||||
["extensions.e10sBlocksEnabling", false],
|
||||
|
||||
// Disable metadata caching for installed add-ons by default
|
||||
["extensions.getAddons.cache.enabled", false],
|
||||
|
||||
// Disable intalling any distribution extensions or add-ons.
|
||||
// Should be set in profile.
|
||||
["extensions.installDistroAddons", false],
|
||||
["extensions.showMismatchUI", false],
|
||||
|
||||
// Turn off extension updates so they do not bother tests
|
||||
["extensions.update.enabled", false],
|
||||
["extensions.update.notifyUser", false],
|
||||
|
||||
// Make sure opening about:addons will not hit the network
|
||||
["extensions.webservice.discoverURL", "http://%(server)s/dummy/discoveryURL"],
|
||||
|
||||
// Allow the application to have focus even it runs in the background
|
||||
["focusmanager.testmode", true],
|
||||
|
||||
// Disable useragent updates
|
||||
["general.useragent.updates.enabled", false],
|
||||
|
||||
// Always use network provider for geolocation tests so we bypass the
|
||||
// macOS dialog raised by the corelocation provider
|
||||
["geo.provider.testing", true],
|
||||
|
||||
// Do not scan Wifi
|
||||
["geo.wifi.scan", false],
|
||||
|
||||
// No hang monitor
|
||||
["hangmonitor.timeout", 0],
|
||||
|
||||
// Show chrome errors and warnings in the error console
|
||||
["javascript.options.showInConsole", true],
|
||||
|
||||
// Make sure the disk cache doesn't get auto disabled
|
||||
["network.http.bypass-cachelock-threshold", 200000],
|
||||
|
||||
// Do not prompt for temporary redirects
|
||||
["network.http.prompt-temp-redirect", false],
|
||||
|
||||
// Disable speculative connections so they are not reported as leaking
|
||||
// when they are hanging around
|
||||
["network.http.speculative-parallel-limit", 0],
|
||||
|
||||
// Do not automatically switch between offline and online
|
||||
["network.manage-offline-status", false],
|
||||
|
||||
// Make sure SNTP requests do not hit the network
|
||||
["network.sntp.pools", "%(server)s"],
|
||||
|
||||
// Local documents have access to all other local documents,
|
||||
// including directory listings
|
||||
["security.fileuri.strict_origin_policy", false],
|
||||
|
||||
// Tests do not wait for the notification button security delay
|
||||
["security.notification_enable_delay", 0],
|
||||
|
||||
// Ensure blocklist updates do not hit the network
|
||||
["services.settings.server", "http://%(server)s/dummy/blocklist/"],
|
||||
|
||||
// Do not automatically fill sign-in forms with known usernames and
|
||||
// passwords
|
||||
["signon.autofillForms", false],
|
||||
|
||||
// Disable password capture, so that tests that include forms are not
|
||||
// influenced by the presence of the persistent doorhanger notification
|
||||
["signon.rememberSignons", false],
|
||||
|
||||
// Disable first-run welcome page
|
||||
["startup.homepage_welcome_url", "about:blank"],
|
||||
["startup.homepage_welcome_url.additional", ""],
|
||||
|
||||
// Prevent starting into safe mode after application crashes
|
||||
["toolkit.startup.max_resumed_crashes", -1],
|
||||
|
||||
]);
|
||||
|
||||
/**
|
||||
* Bootstraps Marionette and handles incoming client connections.
|
||||
*
|
||||
* Once started, it opens a TCP socket sporting the debugger transport
|
||||
* protocol on the provided port. For every new client a Dispatcher is
|
||||
* created.
|
||||
*
|
||||
* @param {number} port
|
||||
* Port for server to listen to.
|
||||
* @param {boolean} forceLocal
|
||||
* Listen only to connections from loopback if true. If false,
|
||||
* accept all connections.
|
||||
* Starting the Marionette server will open a TCP socket sporting the
|
||||
* debugger transport interface on the provided |port|. For every new
|
||||
* connection, a |server.TCPConnection| is created.
|
||||
*/
|
||||
this.MarionetteServer = function (port, forceLocal) {
|
||||
this.port = port;
|
||||
this.forceLocal = forceLocal;
|
||||
this.conns = {};
|
||||
this.nextConnId = 0;
|
||||
this.alive = false;
|
||||
this._acceptConnections = false;
|
||||
server.TCPListener = class {
|
||||
/**
|
||||
* @param {number} port
|
||||
* Port for server to listen to.
|
||||
* @param {boolean=} forceLocal
|
||||
* Listen only to connections from loopback if true (default).
|
||||
* When false, accept all connections.
|
||||
*/
|
||||
constructor (port, forceLocal = true) {
|
||||
this.port = port;
|
||||
this.forceLocal = forceLocal;
|
||||
this.conns = new Set();
|
||||
this.nextConnID = 0;
|
||||
this.alive = false;
|
||||
this._acceptConnections = false;
|
||||
this.alteredPrefs = new Set();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function produces a GeckoDriver.
|
||||
*
|
||||
* Determines application nameto initialise the driver with.
|
||||
*
|
||||
* @return {GeckoDriver}
|
||||
* A driver instance.
|
||||
*/
|
||||
driverFactory () {
|
||||
Preferences.set(PREF_CONTENT_LISTENER, false);
|
||||
return new GeckoDriver(Services.appinfo.name, this);
|
||||
}
|
||||
|
||||
set acceptConnections (value) {
|
||||
if (!value) {
|
||||
logger.info("New connections will no longer be accepted");
|
||||
} else {
|
||||
logger.info("New connections are accepted again");
|
||||
}
|
||||
|
||||
this._acceptConnections = value;
|
||||
}
|
||||
|
||||
start () {
|
||||
if (this.alive) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Preferences.get(PREF_RECOMMENDED)) {
|
||||
// set recommended prefs if they are not already user-defined
|
||||
for (let [k, v] of RECOMMENDED_PREFS) {
|
||||
if (!Preferences.isSet(k)) {
|
||||
logger.debug(`Setting recommended pref ${k} to ${v}`);
|
||||
Preferences.set(k, v);
|
||||
this.alteredPrefs.add(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let flags = Ci.nsIServerSocket.KeepWhenOffline;
|
||||
if (this.forceLocal) {
|
||||
flags |= Ci.nsIServerSocket.LoopbackOnly;
|
||||
}
|
||||
this.listener = new ServerSocket(this.port, flags, 1);
|
||||
this.listener.asyncListen(this);
|
||||
|
||||
this.alive = true;
|
||||
this._acceptConnections = true;
|
||||
}
|
||||
|
||||
stop () {
|
||||
if (!this.alive) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let k of this.alteredPrefs) {
|
||||
logger.debug(`Resetting recommended pref ${k}`);
|
||||
Preferences.reset(k);
|
||||
}
|
||||
this.closeListener();
|
||||
|
||||
this.alteredPrefs.clear();
|
||||
this.alive = false;
|
||||
this._acceptConnections = false;
|
||||
}
|
||||
|
||||
closeListener () {
|
||||
this.listener.close();
|
||||
this.listener = null;
|
||||
}
|
||||
|
||||
onSocketAccepted (serverSocket, clientSocket) {
|
||||
if (!this._acceptConnections) {
|
||||
logger.warn("New connections are currently not accepted");
|
||||
return;
|
||||
}
|
||||
|
||||
let input = clientSocket.openInputStream(0, 0, 0);
|
||||
let output = clientSocket.openOutputStream(0, 0, 0);
|
||||
let transport = new DebuggerTransport(input, output);
|
||||
|
||||
let conn = new server.TCPConnection(
|
||||
this.nextConnID++, transport, this.driverFactory.bind(this));
|
||||
conn.onclose = this.onConnectionClosed.bind(this);
|
||||
this.conns.add(conn);
|
||||
|
||||
logger.debug(`Accepted connection ${conn.id} from ${clientSocket.host}:${clientSocket.port}`);
|
||||
conn.sayHello();
|
||||
transport.ready();
|
||||
}
|
||||
|
||||
onConnectionClosed (conn) {
|
||||
logger.debug(`Closed connection ${conn.id}`);
|
||||
this.conns.delete(conn);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function produces a GeckoDriver.
|
||||
* Marionette client connection.
|
||||
*
|
||||
* Determines application nameto initialise the driver with.
|
||||
* Dispatches packets received to their correct service destinations
|
||||
* and sends back the service endpoint's return values.
|
||||
*
|
||||
* @return {GeckoDriver}
|
||||
* A driver instance.
|
||||
* @param {number} connID
|
||||
* Unique identifier of the connection this dispatcher should handle.
|
||||
* @param {DebuggerTransport} transport
|
||||
* Debugger transport connection to the client.
|
||||
* @param {function(): GeckoDriver} driverFactory
|
||||
* Factory function that produces a |GeckoDriver|.
|
||||
*/
|
||||
MarionetteServer.prototype.driverFactory = function() {
|
||||
let appName = isMulet() ? "B2G" : Services.appinfo.name;
|
||||
let bypassOffline = false;
|
||||
server.TCPConnection = class {
|
||||
constructor (connID, transport, driverFactory) {
|
||||
this.id = connID;
|
||||
this.conn = transport;
|
||||
|
||||
Preferences.set(CONTENT_LISTENER_PREF, false);
|
||||
// transport hooks are TCPConnection#onPacket
|
||||
// and TCPConnection#onClosed
|
||||
this.conn.hooks = this;
|
||||
|
||||
if (bypassOffline) {
|
||||
logger.debug("Bypassing offline status");
|
||||
Preferences.set(MANAGE_OFFLINE_STATUS_PREF, false);
|
||||
Services.io.manageOfflineStatus = false;
|
||||
Services.io.offline = false;
|
||||
// callback for when connection is closed
|
||||
this.onclose = null;
|
||||
|
||||
// last received/sent message ID
|
||||
this.lastID = 0;
|
||||
|
||||
this.driver = driverFactory();
|
||||
|
||||
// lookup of commands sent by server to client by message ID
|
||||
this.commands_ = new Map();
|
||||
}
|
||||
|
||||
return new GeckoDriver(appName, this);
|
||||
};
|
||||
|
||||
MarionetteServer.prototype.__defineSetter__("acceptConnections", function (value) {
|
||||
if (!value) {
|
||||
logger.info("New connections will no longer be accepted");
|
||||
} else {
|
||||
logger.info("New connections are accepted again");
|
||||
/**
|
||||
* Debugger transport callback that cleans up
|
||||
* after a connection is closed.
|
||||
*/
|
||||
onClosed (reason) {
|
||||
this.driver.deleteSession();
|
||||
if (this.onclose) {
|
||||
this.onclose(this);
|
||||
}
|
||||
}
|
||||
|
||||
this._acceptConnections = value;
|
||||
});
|
||||
/**
|
||||
* Callback that receives data packets from the client.
|
||||
*
|
||||
* If the message is a Response, we look up the command previously
|
||||
* issued to the client and run its callback, if any. In case of
|
||||
* a Command, the corresponding is executed.
|
||||
*
|
||||
* @param {Array.<number, number, ?, ?>} data
|
||||
* A four element array where the elements, in sequence, signifies
|
||||
* message type, message ID, method name or error, and parameters
|
||||
* or result.
|
||||
*/
|
||||
onPacket (data) {
|
||||
let msg = Message.fromMsg(data);
|
||||
msg.origin = MessageOrigin.Client;
|
||||
this.log_(msg);
|
||||
|
||||
MarionetteServer.prototype.start = function() {
|
||||
if (this.alive) {
|
||||
return;
|
||||
}
|
||||
let flags = Ci.nsIServerSocket.KeepWhenOffline;
|
||||
if (this.forceLocal) {
|
||||
flags |= Ci.nsIServerSocket.LoopbackOnly;
|
||||
}
|
||||
this.listener = new ServerSocket(this.port, flags, 1);
|
||||
this.listener.asyncListen(this);
|
||||
this.alive = true;
|
||||
this._acceptConnections = true;
|
||||
};
|
||||
|
||||
MarionetteServer.prototype.stop = function() {
|
||||
if (!this.alive) {
|
||||
return;
|
||||
}
|
||||
this.closeListener();
|
||||
this.alive = false;
|
||||
this._acceptConnections = false;
|
||||
};
|
||||
|
||||
MarionetteServer.prototype.closeListener = function() {
|
||||
this.listener.close();
|
||||
this.listener = null;
|
||||
};
|
||||
|
||||
MarionetteServer.prototype.onSocketAccepted = function (
|
||||
serverSocket, clientSocket) {
|
||||
if (!this._acceptConnections) {
|
||||
logger.warn("New connections are currently not accepted");
|
||||
return;
|
||||
if (msg instanceof Response) {
|
||||
let cmd = this.commands_.get(msg.id);
|
||||
this.commands_.delete(msg.id);
|
||||
cmd.onresponse(msg);
|
||||
} else if (msg instanceof Command) {
|
||||
this.lastID = msg.id;
|
||||
this.execute(msg);
|
||||
}
|
||||
}
|
||||
|
||||
let input = clientSocket.openInputStream(0, 0, 0);
|
||||
let output = clientSocket.openOutputStream(0, 0, 0);
|
||||
let transport = new DebuggerTransport(input, output);
|
||||
let connId = "conn" + this.nextConnId++;
|
||||
/**
|
||||
* Executes a WebDriver command and sends back a response when it has
|
||||
* finished executing.
|
||||
*
|
||||
* Commands implemented in GeckoDriver and registered in its
|
||||
* {@code GeckoDriver.commands} attribute. The return values from
|
||||
* commands are expected to be Promises. If the resolved value of said
|
||||
* promise is not an object, the response body will be wrapped in
|
||||
* an object under a "value" field.
|
||||
*
|
||||
* If the command implementation sends the response itself by calling
|
||||
* {@code resp.send()}, the response is guaranteed to not be sent twice.
|
||||
*
|
||||
* Errors thrown in commands are marshaled and sent back, and if they
|
||||
* are not WebDriverError instances, they are additionally propagated
|
||||
* and reported to {@code Components.utils.reportError}.
|
||||
*
|
||||
* @param {Command} cmd
|
||||
* The requested command to execute.
|
||||
*/
|
||||
execute (cmd) {
|
||||
let resp = new Response(cmd.id, this.send.bind(this));
|
||||
let sendResponse = () => resp.sendConditionally(resp => !resp.sent);
|
||||
let sendError = resp.sendError.bind(resp);
|
||||
|
||||
let dispatcher = new Dispatcher(connId, transport, this.driverFactory.bind(this));
|
||||
dispatcher.onclose = this.onConnectionClosed.bind(this);
|
||||
this.conns[connId] = dispatcher;
|
||||
let req = Task.spawn(function*() {
|
||||
let fn = this.driver.commands[cmd.name];
|
||||
if (typeof fn == "undefined") {
|
||||
throw new UnknownCommandError(cmd.name);
|
||||
}
|
||||
|
||||
logger.debug(`Accepted connection ${connId} from ${clientSocket.host}:${clientSocket.port}`);
|
||||
dispatcher.sayHello();
|
||||
transport.ready();
|
||||
if (cmd.name !== "newSession") {
|
||||
assert.session(this.driver);
|
||||
}
|
||||
|
||||
let rv = yield fn.bind(this.driver)(cmd, resp);
|
||||
|
||||
if (typeof rv != "undefined") {
|
||||
if (typeof rv != "object") {
|
||||
resp.body = {value: rv};
|
||||
} else {
|
||||
resp.body = rv;
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
req.then(sendResponse, sendError).catch(error.report);
|
||||
}
|
||||
|
||||
sendError (err, cmdID) {
|
||||
let resp = new Response(cmdID, this.send.bind(this));
|
||||
resp.sendError(err);
|
||||
}
|
||||
|
||||
/**
|
||||
* When a client connects we send across a JSON Object defining the
|
||||
* protocol level.
|
||||
*
|
||||
* This is the only message sent by Marionette that does not follow
|
||||
* the regular message format.
|
||||
*/
|
||||
sayHello () {
|
||||
let whatHo = {
|
||||
applicationType: "gecko",
|
||||
marionetteProtocol: PROTOCOL_VERSION,
|
||||
};
|
||||
this.sendRaw(whatHo);
|
||||
};
|
||||
|
||||
/**
|
||||
* Delegates message to client based on the provided {@code cmdID}.
|
||||
* The message is sent over the debugger transport socket.
|
||||
*
|
||||
* The command ID is a unique identifier assigned to the client's request
|
||||
* that is used to distinguish the asynchronous responses.
|
||||
*
|
||||
* Whilst responses to commands are synchronous and must be sent in the
|
||||
* correct order.
|
||||
*
|
||||
* @param {Command,Response} msg
|
||||
* The command or response to send.
|
||||
*/
|
||||
send (msg) {
|
||||
msg.origin = MessageOrigin.Server;
|
||||
if (msg instanceof Command) {
|
||||
this.commands_.set(msg.id, msg);
|
||||
this.sendToEmulator(msg);
|
||||
} else if (msg instanceof Response) {
|
||||
this.sendToClient(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// Low-level methods:
|
||||
|
||||
/**
|
||||
* Send given response to the client over the debugger transport socket.
|
||||
*
|
||||
* @param {Response} resp
|
||||
* The response to send back to the client.
|
||||
*/
|
||||
sendToClient (resp) {
|
||||
this.driver.responseCompleted();
|
||||
this.sendMessage(resp);
|
||||
};
|
||||
|
||||
/**
|
||||
* Marshal message to the Marionette message format and send it.
|
||||
*
|
||||
* @param {Command,Response} msg
|
||||
* The message to send.
|
||||
*/
|
||||
sendMessage (msg) {
|
||||
this.log_(msg);
|
||||
let payload = msg.toMsg();
|
||||
this.sendRaw(payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the given payload over the debugger transport socket to the
|
||||
* connected client.
|
||||
*
|
||||
* @param {Object} payload
|
||||
* The payload to ship.
|
||||
*/
|
||||
sendRaw (payload) {
|
||||
this.conn.send(payload);
|
||||
}
|
||||
|
||||
log_ (msg) {
|
||||
let a = (msg.origin == MessageOrigin.Client ? " -> " : " <- ");
|
||||
let s = JSON.stringify(msg.toMsg());
|
||||
logger.trace(this.id + a + s);
|
||||
}
|
||||
|
||||
toString () {
|
||||
return `[object server.TCPConnection ${this.id}]`;
|
||||
}
|
||||
};
|
||||
|
||||
MarionetteServer.prototype.onConnectionClosed = function (conn) {
|
||||
let id = conn.connId;
|
||||
delete this.conns[id];
|
||||
logger.debug(`Closed connection ${id}`);
|
||||
};
|
||||
|
||||
function isMulet() {
|
||||
return Preferences.get("b2g.is_mulet", false);
|
||||
}
|
||||
|
|
|
@ -42,9 +42,9 @@ session.Timeouts = class {
|
|||
|
||||
toJSON () {
|
||||
return {
|
||||
"implicit": this.implicit,
|
||||
"page load": this.pageLoad,
|
||||
"script": this.script,
|
||||
implicit: this.implicit,
|
||||
pageLoad: this.pageLoad,
|
||||
script: this.script,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ session.Timeouts = class {
|
|||
t.script = ms;
|
||||
break;
|
||||
|
||||
case "page load":
|
||||
case "pageLoad":
|
||||
t.pageLoad = ms;
|
||||
break;
|
||||
|
||||
|
|
|
@ -29,21 +29,21 @@ add_test(function test_Timeouts_toString() {
|
|||
|
||||
add_test(function test_Timeouts_toJSON() {
|
||||
let ts = new session.Timeouts();
|
||||
deepEqual(ts.toJSON(), {"implicit": 0, "page load": 300000, "script": 30000});
|
||||
deepEqual(ts.toJSON(), {"implicit": 0, "pageLoad": 300000, "script": 30000});
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_Timeouts_fromJSON() {
|
||||
let json = {
|
||||
"implicit": 10,
|
||||
"page load": 20,
|
||||
"script": 30,
|
||||
implicit: 10,
|
||||
pageLoad: 20,
|
||||
script: 30,
|
||||
};
|
||||
let ts = session.Timeouts.fromJSON(json);
|
||||
equal(ts.implicit, json["implicit"]);
|
||||
equal(ts.pageLoad, json["page load"]);
|
||||
equal(ts.script, json["script"]);
|
||||
equal(ts.implicit, json.implicit);
|
||||
equal(ts.pageLoad, json.pageLoad);
|
||||
equal(ts.script, json.script);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
|
|
@ -365,3 +365,8 @@ user_pref("signon.rememberSignons", false);
|
|||
|
||||
// Enable form autofill feature testing.
|
||||
user_pref("browser.formautofill.experimental", true);
|
||||
|
||||
// Disable all recommended Marionette preferences for Gecko tests.
|
||||
// The prefs recommended by Marionette are typically geared towards
|
||||
// consumer automation; not vendor testing.
|
||||
user_pref("marionette.prefs.recommended", false);
|
||||
|
|
|
@ -148,8 +148,8 @@ class FirefoxBrowser(Browser):
|
|||
|
||||
self.profile = FirefoxProfile(locations=locations,
|
||||
preferences=preferences)
|
||||
self.profile.set_preferences({"marionette.defaultPrefs.enabled": True,
|
||||
"marionette.defaultPrefs.port": self.marionette_port,
|
||||
self.profile.set_preferences({"marionette.enabled": True,
|
||||
"marionette.port": self.marionette_port,
|
||||
"dom.disable_open_during_load": False,
|
||||
"network.dns.localDomains": ",".join(hostnames),
|
||||
"network.proxy.type": 0,
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
"dbg-server.jsm": ["DebuggerServer", "ActorPool", "OriginalLocation"],
|
||||
"debug.js": ["NS_ASSERT"],
|
||||
"declined.js": ["DeclinedEngines"],
|
||||
"dispatcher.js": ["Dispatcher"],
|
||||
"dispatcher.js": ["dispatcher"],
|
||||
"distribution.js": ["DistributionCustomizer"],
|
||||
"DNSTypes.jsm": ["DNS_QUERY_RESPONSE_CODES", "DNS_AUTHORITATIVE_ANSWER_CODES", "DNS_CLASS_CODES", "DNS_RECORD_TYPES"],
|
||||
"doctor.js": ["Doctor"],
|
||||
|
@ -193,7 +193,7 @@
|
|||
"require.js": ["require"],
|
||||
"RTCStatsReport.jsm": ["convertToRTCStatsReport"],
|
||||
"scratchpad-manager.jsm": ["ScratchpadManager"],
|
||||
"server.js": ["MarionetteServer"],
|
||||
"server.js": ["server"],
|
||||
"service.js": ["Service"],
|
||||
"SharedPromptUtils.jsm": ["PromptUtils", "EnableDelayHelper"],
|
||||
"ShutdownLeaksCollector.jsm": ["ContentCollector"],
|
||||
|
|
|
@ -1357,13 +1357,6 @@ PuppetWidget::GetScreenDimensions()
|
|||
return nsIntSize(r.width, r.height);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PuppetScreen::GetId(uint32_t *outId)
|
||||
{
|
||||
*outId = 1;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PuppetScreen::GetRect(int32_t *outLeft, int32_t *outTop,
|
||||
int32_t *outWidth, int32_t *outHeight)
|
||||
|
@ -1397,20 +1390,6 @@ PuppetScreen::GetColorDepth(int32_t *aColorDepth)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PuppetScreen::GetRotation(uint32_t* aRotation)
|
||||
{
|
||||
NS_WARNING("Attempt to get screen rotation through nsIScreen::GetRotation(). Nothing should know or care this in sandboxed contexts. If you want *orientation*, use hal.");
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PuppetScreen::SetRotation(uint32_t aRotation)
|
||||
{
|
||||
NS_WARNING("Attempt to set screen rotation through nsIScreen::GetRotation(). Nothing should know or care this in sandboxed contexts. If you want *orientation*, use hal.");
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(PuppetScreenManager, nsIScreenManager)
|
||||
|
||||
PuppetScreenManager::PuppetScreenManager()
|
||||
|
@ -1422,14 +1401,6 @@ PuppetScreenManager::~PuppetScreenManager()
|
|||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PuppetScreenManager::ScreenForId(uint32_t aId,
|
||||
nsIScreen** outScreen)
|
||||
{
|
||||
NS_IF_ADDREF(*outScreen = mOneScreen.get());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PuppetScreenManager::GetPrimaryScreen(nsIScreen** outScreen)
|
||||
{
|
||||
|
@ -1447,20 +1418,6 @@ PuppetScreenManager::ScreenForRect(int32_t inLeft,
|
|||
return GetPrimaryScreen(outScreen);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PuppetScreenManager::ScreenForNativeWidget(void* aWidget,
|
||||
nsIScreen** outScreen)
|
||||
{
|
||||
return GetPrimaryScreen(outScreen);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PuppetScreenManager::GetNumberOfScreens(uint32_t* aNumberOfScreens)
|
||||
{
|
||||
*aNumberOfScreens = 1;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PuppetScreenManager::GetSystemDefaultScale(float *aDefaultScale)
|
||||
{
|
||||
|
|
|
@ -443,13 +443,10 @@ public:
|
|||
explicit PuppetScreen(void* nativeScreen);
|
||||
~PuppetScreen();
|
||||
|
||||
NS_IMETHOD GetId(uint32_t* aId) override;
|
||||
NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight) override;
|
||||
NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight) override;
|
||||
NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth) override;
|
||||
NS_IMETHOD GetColorDepth(int32_t* aColorDepth) override;
|
||||
NS_IMETHOD GetRotation(uint32_t* aRotation) override;
|
||||
NS_IMETHOD SetRotation(uint32_t aRotation) override;
|
||||
};
|
||||
|
||||
class PuppetScreenManager final : public nsIScreenManager
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; -*- */
|
||||
/* vim: set sw=4 ts=8 et 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 "Screen.h"
|
||||
|
||||
#include "mozilla/dom/DOMTypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
NS_IMPL_ISUPPORTS(Screen, nsIScreen)
|
||||
|
||||
Screen::Screen(LayoutDeviceIntRect aRect, LayoutDeviceIntRect aAvailRect,
|
||||
uint32_t aPixelDepth, uint32_t aColorDepth,
|
||||
DesktopToLayoutDeviceScale aContentsScale,
|
||||
CSSToLayoutDeviceScale aDefaultCssScale)
|
||||
: mRect(aRect)
|
||||
, mAvailRect(aAvailRect)
|
||||
, mRectDisplayPix(RoundedToInt(aRect / aContentsScale))
|
||||
, mAvailRectDisplayPix(RoundedToInt(aAvailRect / aContentsScale))
|
||||
, mPixelDepth(aPixelDepth)
|
||||
, mColorDepth(aColorDepth)
|
||||
, mContentsScale(aContentsScale)
|
||||
, mDefaultCssScale(aDefaultCssScale)
|
||||
{
|
||||
}
|
||||
|
||||
Screen::Screen(const mozilla::dom::ScreenDetails& aScreen)
|
||||
: mRect(aScreen.rect())
|
||||
, mAvailRect(aScreen.availRect())
|
||||
, mRectDisplayPix(aScreen.rectDisplayPix())
|
||||
, mAvailRectDisplayPix(aScreen.availRectDisplayPix())
|
||||
, mPixelDepth(aScreen.pixelDepth())
|
||||
, mColorDepth(aScreen.colorDepth())
|
||||
, mContentsScale(aScreen.contentsScaleFactor())
|
||||
, mDefaultCssScale(aScreen.defaultCSSScaleFactor())
|
||||
{
|
||||
}
|
||||
|
||||
Screen::Screen(const Screen& aOther)
|
||||
: mRect(aOther.mRect)
|
||||
, mAvailRect(aOther.mAvailRect)
|
||||
, mRectDisplayPix(aOther.mRectDisplayPix)
|
||||
, mAvailRectDisplayPix(aOther.mAvailRectDisplayPix)
|
||||
, mPixelDepth(aOther.mPixelDepth)
|
||||
, mColorDepth(aOther.mColorDepth)
|
||||
, mContentsScale(aOther.mContentsScale)
|
||||
, mDefaultCssScale(aOther.mDefaultCssScale)
|
||||
{
|
||||
}
|
||||
|
||||
mozilla::dom::ScreenDetails
|
||||
Screen::ToScreenDetails()
|
||||
{
|
||||
return mozilla::dom::ScreenDetails(
|
||||
mRect, mRectDisplayPix, mAvailRect, mAvailRectDisplayPix,
|
||||
mPixelDepth, mColorDepth, mContentsScale, mDefaultCssScale);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Screen::GetRect(int32_t* aOutLeft,
|
||||
int32_t* aOutTop,
|
||||
int32_t* aOutWidth,
|
||||
int32_t* aOutHeight)
|
||||
{
|
||||
*aOutLeft = mRect.x;
|
||||
*aOutTop = mRect.y;
|
||||
*aOutWidth = mRect.width;
|
||||
*aOutHeight = mRect.height;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Screen::GetRectDisplayPix(int32_t* aOutLeft,
|
||||
int32_t* aOutTop,
|
||||
int32_t* aOutWidth,
|
||||
int32_t* aOutHeight)
|
||||
{
|
||||
*aOutLeft = mRectDisplayPix.x;
|
||||
*aOutTop = mRectDisplayPix.y;
|
||||
*aOutWidth = mRectDisplayPix.width;
|
||||
*aOutHeight = mRectDisplayPix.height;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Screen::GetAvailRect(int32_t* aOutLeft,
|
||||
int32_t* aOutTop,
|
||||
int32_t* aOutWidth,
|
||||
int32_t* aOutHeight)
|
||||
{
|
||||
*aOutLeft = mAvailRect.x;
|
||||
*aOutTop = mAvailRect.y;
|
||||
*aOutWidth = mAvailRect.width;
|
||||
*aOutHeight = mAvailRect.height;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Screen::GetAvailRectDisplayPix(int32_t* aOutLeft,
|
||||
int32_t* aOutTop,
|
||||
int32_t* aOutWidth,
|
||||
int32_t* aOutHeight)
|
||||
{
|
||||
*aOutLeft = mAvailRectDisplayPix.x;
|
||||
*aOutTop = mAvailRectDisplayPix.y;
|
||||
*aOutWidth = mAvailRectDisplayPix.width;
|
||||
*aOutHeight = mAvailRectDisplayPix.height;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Screen::GetPixelDepth(int32_t* aPixelDepth)
|
||||
{
|
||||
*aPixelDepth = mPixelDepth;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Screen::GetColorDepth(int32_t* aColorDepth)
|
||||
{
|
||||
*aColorDepth = mColorDepth;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Screen::GetContentsScaleFactor(double *aOutScale)
|
||||
{
|
||||
*aOutScale = mContentsScale.scale;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Screen::GetDefaultCSSScaleFactor(double *aOutScale)
|
||||
{
|
||||
*aOutScale = mDefaultCssScale.scale;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,55 @@
|
|||
/* -*- 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_widget_Screen_h
|
||||
#define mozilla_widget_Screen_h
|
||||
|
||||
#include "nsIScreen.h"
|
||||
|
||||
#include "Units.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class ScreenDetails;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
class Screen final : public nsIScreen
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISCREEN
|
||||
|
||||
Screen(LayoutDeviceIntRect aRect, LayoutDeviceIntRect aAvailRect,
|
||||
uint32_t aPixelDepth, uint32_t aColorDepth,
|
||||
DesktopToLayoutDeviceScale aContentsScale,
|
||||
CSSToLayoutDeviceScale aDefaultCssScale);
|
||||
explicit Screen(const mozilla::dom::ScreenDetails& aScreenDetails);
|
||||
Screen(const Screen& aOther);
|
||||
|
||||
mozilla::dom::ScreenDetails ToScreenDetails();
|
||||
|
||||
private:
|
||||
virtual ~Screen() {}
|
||||
|
||||
LayoutDeviceIntRect mRect;
|
||||
LayoutDeviceIntRect mAvailRect;
|
||||
DesktopIntRect mRectDisplayPix;
|
||||
DesktopIntRect mAvailRectDisplayPix;
|
||||
uint32_t mPixelDepth;
|
||||
uint32_t mColorDepth;
|
||||
DesktopToLayoutDeviceScale mContentsScale;
|
||||
CSSToLayoutDeviceScale mDefaultCssScale;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
/* -*- 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 "ScreenManager.h"
|
||||
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
|
||||
static LazyLogModule sScreenLog("WidgetScreen");
|
||||
|
||||
NS_IMPL_ISUPPORTS(ScreenManager, nsIScreenManager)
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
ScreenManager::ScreenManager()
|
||||
{
|
||||
}
|
||||
|
||||
ScreenManager::~ScreenManager()
|
||||
{
|
||||
}
|
||||
|
||||
static StaticRefPtr<ScreenManager> sSingleton;
|
||||
|
||||
ScreenManager&
|
||||
ScreenManager::GetSingleton()
|
||||
{
|
||||
if (!sSingleton) {
|
||||
sSingleton = new ScreenManager();
|
||||
ClearOnShutdown(&sSingleton);
|
||||
}
|
||||
return *sSingleton;
|
||||
}
|
||||
|
||||
already_AddRefed<ScreenManager>
|
||||
ScreenManager::GetAddRefedSingleton()
|
||||
{
|
||||
RefPtr<ScreenManager> sm = &GetSingleton();
|
||||
return sm.forget();
|
||||
}
|
||||
|
||||
void
|
||||
ScreenManager::SetHelper(UniquePtr<Helper> aHelper)
|
||||
{
|
||||
mHelper = Move(aHelper);
|
||||
}
|
||||
|
||||
void
|
||||
ScreenManager::Refresh(nsTArray<RefPtr<Screen>>&& aScreens)
|
||||
{
|
||||
MOZ_LOG(sScreenLog, LogLevel::Debug, ("Refresh screens"));
|
||||
|
||||
mScreenList = Move(aScreens);
|
||||
|
||||
CopyScreensToAllRemotesIfIsParent();
|
||||
}
|
||||
|
||||
void
|
||||
ScreenManager::Refresh(nsTArray<mozilla::dom::ScreenDetails>&& aScreens)
|
||||
{
|
||||
MOZ_LOG(sScreenLog, LogLevel::Debug, ("Refresh screens from IPC"));
|
||||
|
||||
mScreenList.Clear();
|
||||
for (auto& screen : aScreens) {
|
||||
mScreenList.AppendElement(new Screen(screen));
|
||||
}
|
||||
|
||||
CopyScreensToAllRemotesIfIsParent();
|
||||
}
|
||||
|
||||
template<class Range>
|
||||
void
|
||||
ScreenManager::CopyScreensToRemoteRange(Range aRemoteRange)
|
||||
{
|
||||
AutoTArray<ScreenDetails, 4> screens;
|
||||
for (auto& screen : mScreenList) {
|
||||
screens.AppendElement(screen->ToScreenDetails());
|
||||
}
|
||||
for (auto cp : aRemoteRange) {
|
||||
MOZ_LOG(sScreenLog, LogLevel::Debug, ("Send screens to [Pid %d]", cp->Pid()));
|
||||
if (!cp->SendRefreshScreens(screens)) {
|
||||
MOZ_LOG(sScreenLog, LogLevel::Error,
|
||||
("SendRefreshScreens to [Pid %d] failed", cp->Pid()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ScreenManager::CopyScreensToRemote(ContentParent* aContentParent)
|
||||
{
|
||||
MOZ_ASSERT(aContentParent);
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
auto range = { aContentParent };
|
||||
CopyScreensToRemoteRange(range);
|
||||
}
|
||||
|
||||
void
|
||||
ScreenManager::CopyScreensToAllRemotesIfIsParent()
|
||||
{
|
||||
if (XRE_IsContentProcess()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_LOG(sScreenLog, LogLevel::Debug, ("Refreshing all ContentParents"));
|
||||
|
||||
CopyScreensToRemoteRange(ContentParent::AllProcesses(ContentParent::eLive));
|
||||
}
|
||||
|
||||
// Returns the screen that contains the rectangle. If the rect overlaps
|
||||
// multiple screens, it picks the screen with the greatest area of intersection.
|
||||
//
|
||||
// The coordinates are in desktop pixels.
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
ScreenManager::ScreenForRect(int32_t aX, int32_t aY,
|
||||
int32_t aWidth, int32_t aHeight,
|
||||
nsIScreen** aOutScreen)
|
||||
{
|
||||
if (mScreenList.IsEmpty()) {
|
||||
MOZ_LOG(sScreenLog, LogLevel::Warning,
|
||||
("No screen available. This can happen in xpcshell."));
|
||||
RefPtr<Screen> ret = new Screen(LayoutDeviceIntRect(), LayoutDeviceIntRect(),
|
||||
0, 0,
|
||||
DesktopToLayoutDeviceScale(),
|
||||
CSSToLayoutDeviceScale());
|
||||
ret.forget(aOutScreen);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Optimize for the common case. If the number of screens is only
|
||||
// one then just return the primary screen.
|
||||
if (mScreenList.Length() == 1) {
|
||||
return GetPrimaryScreen(aOutScreen);
|
||||
}
|
||||
|
||||
// which screen should we return?
|
||||
Screen* which = mScreenList[0].get();
|
||||
|
||||
// walk the list of screens and find the one that has the most
|
||||
// surface area.
|
||||
uint32_t area = 0;
|
||||
DesktopIntRect windowRect(aX, aY, aWidth, aHeight);
|
||||
for (auto& screen : mScreenList) {
|
||||
int32_t x, y, width, height;
|
||||
x = y = width = height = 0;
|
||||
screen->GetRectDisplayPix(&x, &y, &width, &height);
|
||||
// calculate the surface area
|
||||
DesktopIntRect screenRect(x, y, width, height);
|
||||
screenRect.IntersectRect(screenRect, windowRect);
|
||||
uint32_t tempArea = screenRect.width * screenRect.height;
|
||||
if (tempArea >= area) {
|
||||
which = screen.get();
|
||||
area = tempArea;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<Screen> ret = which;
|
||||
ret.forget(aOutScreen);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// The screen with the menubar/taskbar. This shouldn't be needed very
|
||||
// often.
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
ScreenManager::GetPrimaryScreen(nsIScreen** aPrimaryScreen)
|
||||
{
|
||||
if (mScreenList.IsEmpty()) {
|
||||
MOZ_LOG(sScreenLog, LogLevel::Warning,
|
||||
("No screen available. This can happen in xpcshell."));
|
||||
RefPtr<Screen> ret = new Screen(LayoutDeviceIntRect(), LayoutDeviceIntRect(),
|
||||
0, 0,
|
||||
DesktopToLayoutDeviceScale(),
|
||||
CSSToLayoutDeviceScale());
|
||||
ret.forget(aPrimaryScreen);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<Screen> ret = mScreenList[0];
|
||||
ret.forget(aPrimaryScreen);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ScreenManager::GetSystemDefaultScale(float* aDefaultScale)
|
||||
{
|
||||
if (mHelper) {
|
||||
*aDefaultScale = mHelper->GetSystemDefaultScale();
|
||||
return NS_OK;
|
||||
}
|
||||
*aDefaultScale = 1;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,65 @@
|
|||
/* -*- 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_widget_ScreenManager_h
|
||||
#define mozilla_widget_ScreenManager_h
|
||||
|
||||
#include "nsIScreenManager.h"
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/widget/Screen.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class ContentParent;
|
||||
class ScreenDetails;
|
||||
}
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
class ScreenManager final : public nsIScreenManager
|
||||
{
|
||||
public:
|
||||
class Helper
|
||||
{
|
||||
public:
|
||||
virtual float GetSystemDefaultScale() = 0;
|
||||
virtual ~Helper() {};
|
||||
};
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISCREENMANAGER
|
||||
|
||||
static ScreenManager& GetSingleton();
|
||||
static already_AddRefed<ScreenManager> GetAddRefedSingleton();
|
||||
|
||||
void SetHelper(UniquePtr<Helper> aHelper);
|
||||
void Refresh(nsTArray<RefPtr<Screen>>&& aScreens);
|
||||
void Refresh(nsTArray<mozilla::dom::ScreenDetails>&& aScreens);
|
||||
void CopyScreensToRemote(mozilla::dom::ContentParent* aContentParent);
|
||||
|
||||
private:
|
||||
ScreenManager();
|
||||
virtual ~ScreenManager();
|
||||
|
||||
template<class Range>
|
||||
void CopyScreensToRemoteRange(Range aRemoteRange);
|
||||
void CopyScreensToAllRemotesIfIsParent();
|
||||
|
||||
AutoTArray<RefPtr<Screen>, 4> mScreenList;
|
||||
UniquePtr<Helper> mHelper;
|
||||
};
|
||||
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_widget_ScreenManager_h
|
|
@ -1,213 +0,0 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; -*- */
|
||||
/* vim: set sw=4 ts=8 et 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 "mozilla/Unused.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIAppShell.h"
|
||||
#include "nsScreenManagerProxy.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsWidgetsCID.h"
|
||||
#include "ScreenProxy.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
|
||||
|
||||
ScreenProxy::ScreenProxy(nsScreenManagerProxy* aScreenManager, ScreenDetails aDetails)
|
||||
: mContentsScaleFactor(0)
|
||||
, mDefaultCSSScaleFactor(0)
|
||||
, mScreenManager(aScreenManager)
|
||||
, mId(0)
|
||||
, mPixelDepth(0)
|
||||
, mColorDepth(0)
|
||||
, mCacheValid(false)
|
||||
, mCacheWillInvalidate(false)
|
||||
{
|
||||
PopulateByDetails(aDetails);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ScreenProxy::GetId(uint32_t *outId)
|
||||
{
|
||||
*outId = mId;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ScreenProxy::GetRect(int32_t *outLeft,
|
||||
int32_t *outTop,
|
||||
int32_t *outWidth,
|
||||
int32_t *outHeight)
|
||||
{
|
||||
if (!EnsureCacheIsValid()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*outLeft = mRect.x;
|
||||
*outTop = mRect.y;
|
||||
*outWidth = mRect.width;
|
||||
*outHeight = mRect.height;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ScreenProxy::GetRectDisplayPix(int32_t *outLeft,
|
||||
int32_t *outTop,
|
||||
int32_t *outWidth,
|
||||
int32_t *outHeight)
|
||||
{
|
||||
if (!EnsureCacheIsValid()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*outLeft = mRectDisplayPix.x;
|
||||
*outTop = mRectDisplayPix.y;
|
||||
*outWidth = mRectDisplayPix.width;
|
||||
*outHeight = mRectDisplayPix.height;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ScreenProxy::GetAvailRect(int32_t *outLeft,
|
||||
int32_t *outTop,
|
||||
int32_t *outWidth,
|
||||
int32_t *outHeight)
|
||||
{
|
||||
if (!EnsureCacheIsValid()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*outLeft = mAvailRect.x;
|
||||
*outTop = mAvailRect.y;
|
||||
*outWidth = mAvailRect.width;
|
||||
*outHeight = mAvailRect.height;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ScreenProxy::GetAvailRectDisplayPix(int32_t *outLeft,
|
||||
int32_t *outTop,
|
||||
int32_t *outWidth,
|
||||
int32_t *outHeight)
|
||||
{
|
||||
if (!EnsureCacheIsValid()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*outLeft = mAvailRectDisplayPix.x;
|
||||
*outTop = mAvailRectDisplayPix.y;
|
||||
*outWidth = mAvailRectDisplayPix.width;
|
||||
*outHeight = mAvailRectDisplayPix.height;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ScreenProxy::GetPixelDepth(int32_t *aPixelDepth)
|
||||
{
|
||||
if (!EnsureCacheIsValid()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*aPixelDepth = mPixelDepth;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ScreenProxy::GetColorDepth(int32_t *aColorDepth)
|
||||
{
|
||||
if (!EnsureCacheIsValid()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*aColorDepth = mColorDepth;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ScreenProxy::GetContentsScaleFactor(double* aContentsScaleFactor)
|
||||
{
|
||||
if (!EnsureCacheIsValid()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*aContentsScaleFactor = mContentsScaleFactor;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ScreenProxy::GetDefaultCSSScaleFactor(double* aScaleFactor)
|
||||
{
|
||||
if (!EnsureCacheIsValid()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*aScaleFactor = mDefaultCSSScaleFactor;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ScreenProxy::PopulateByDetails(ScreenDetails aDetails)
|
||||
{
|
||||
mId = aDetails.id();
|
||||
mRect = nsIntRect(aDetails.rect());
|
||||
mRectDisplayPix = nsIntRect(aDetails.rectDisplayPix());
|
||||
mAvailRect = nsIntRect(aDetails.availRect());
|
||||
mAvailRectDisplayPix = nsIntRect(aDetails.availRectDisplayPix());
|
||||
mPixelDepth = aDetails.pixelDepth();
|
||||
mColorDepth = aDetails.colorDepth();
|
||||
mContentsScaleFactor = aDetails.contentsScaleFactor();
|
||||
mDefaultCSSScaleFactor = aDetails.defaultCSSScaleFactor();
|
||||
}
|
||||
|
||||
bool
|
||||
ScreenProxy::EnsureCacheIsValid()
|
||||
{
|
||||
if (mCacheValid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
// Kick off a synchronous IPC call to the parent to get the
|
||||
// most up-to-date information.
|
||||
ScreenDetails details;
|
||||
Unused << mScreenManager->SendScreenRefresh(mId, &details, &success);
|
||||
if (!success) {
|
||||
NS_WARNING("Updating a ScreenProxy in the child process failed on parent side.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PopulateByDetails(details);
|
||||
mCacheValid = true;
|
||||
|
||||
InvalidateCacheOnNextTick();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ScreenProxy::InvalidateCacheOnNextTick()
|
||||
{
|
||||
if (mCacheWillInvalidate) {
|
||||
return;
|
||||
}
|
||||
|
||||
mCacheWillInvalidate = true;
|
||||
|
||||
nsContentUtils::RunInStableState(NewRunnableMethod(this, &ScreenProxy::InvalidateCache));
|
||||
}
|
||||
|
||||
void
|
||||
ScreenProxy::InvalidateCache()
|
||||
{
|
||||
mCacheValid = false;
|
||||
mCacheWillInvalidate = false;
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; -*- */
|
||||
/* vim: set sw=4 ts=8 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_widget_ScreenProxy_h
|
||||
#define mozilla_widget_ScreenProxy_h
|
||||
|
||||
#include "nsBaseScreen.h"
|
||||
#include "mozilla/dom/PScreenManagerChild.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
|
||||
class nsScreenManagerProxy;
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
class ScreenProxy : public nsBaseScreen
|
||||
{
|
||||
public:
|
||||
ScreenProxy(nsScreenManagerProxy* aScreenManager,
|
||||
mozilla::dom::ScreenDetails aDetails);
|
||||
~ScreenProxy() {};
|
||||
|
||||
NS_IMETHOD GetId(uint32_t* aId) override;
|
||||
|
||||
NS_IMETHOD GetRect(int32_t* aLeft,
|
||||
int32_t* aTop,
|
||||
int32_t* aWidth,
|
||||
int32_t* aHeight) override;
|
||||
NS_IMETHOD GetRectDisplayPix(int32_t* aLeft,
|
||||
int32_t* aTop,
|
||||
int32_t* aWidth,
|
||||
int32_t* aHeight) override;
|
||||
NS_IMETHOD GetAvailRect(int32_t* aLeft,
|
||||
int32_t* aTop,
|
||||
int32_t* aWidth,
|
||||
int32_t* aHeight) override;
|
||||
NS_IMETHOD GetAvailRectDisplayPix(int32_t* aLeft,
|
||||
int32_t* aTop,
|
||||
int32_t* aWidth,
|
||||
int32_t* aHeight) override;
|
||||
NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth) override;
|
||||
NS_IMETHOD GetColorDepth(int32_t* aColorDepth) override;
|
||||
|
||||
NS_IMETHOD GetContentsScaleFactor(double* aContentsScaleFactor) override;
|
||||
NS_IMETHOD GetDefaultCSSScaleFactor(double* aScaleFactor) override;
|
||||
|
||||
private:
|
||||
|
||||
void PopulateByDetails(mozilla::dom::ScreenDetails aDetails);
|
||||
bool EnsureCacheIsValid();
|
||||
void InvalidateCacheOnNextTick();
|
||||
void InvalidateCache();
|
||||
|
||||
double mContentsScaleFactor;
|
||||
double mDefaultCSSScaleFactor;
|
||||
RefPtr<nsScreenManagerProxy> mScreenManager;
|
||||
uint32_t mId;
|
||||
int32_t mPixelDepth;
|
||||
int32_t mColorDepth;
|
||||
nsIntRect mRect;
|
||||
nsIntRect mRectDisplayPix;
|
||||
nsIntRect mAvailRect;
|
||||
nsIntRect mAvailRectDisplayPix;
|
||||
bool mCacheValid;
|
||||
bool mCacheWillInvalidate;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
|
@ -16,6 +16,8 @@
|
|||
#include "ProfilerMarkers.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla::layers;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
CompositorVsyncDispatcher::CompositorVsyncDispatcher()
|
||||
|
|
|
@ -728,7 +728,8 @@ NS_IMPL_ISUPPORTS(nsAndroidBridge,
|
|||
nsIAndroidBridge,
|
||||
nsIObserver)
|
||||
|
||||
nsAndroidBridge::nsAndroidBridge()
|
||||
nsAndroidBridge::nsAndroidBridge() :
|
||||
mAudibleWindowsNum(0)
|
||||
{
|
||||
if (jni::IsAvailable()) {
|
||||
RefPtr<widget::EventDispatcher> dispatcher = new widget::EventDispatcher();
|
||||
|
@ -803,45 +804,28 @@ nsAndroidBridge::Observe(nsISupports* aSubject, const char* aTopic,
|
|||
{
|
||||
if (!strcmp(aTopic, "xpcom-shutdown")) {
|
||||
RemoveObservers();
|
||||
} else if (!strcmp(aTopic, "media-playback")) {
|
||||
ALOG_BRIDGE("nsAndroidBridge::Observe, get media-playback event.");
|
||||
|
||||
nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
|
||||
if (!wrapper) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint64_t windowId = 0;
|
||||
nsresult rv = wrapper->GetData(&windowId);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
} else if (!strcmp(aTopic, "audio-playback")) {
|
||||
ALOG_BRIDGE("nsAndroidBridge::Observe, get audio-playback event.");
|
||||
|
||||
nsAutoString activeStr(aData);
|
||||
bool isPlaying = activeStr.EqualsLiteral("active");
|
||||
UpdateAudioPlayingWindows(windowId, isPlaying);
|
||||
UpdateAudioPlayingWindows(isPlaying);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsAndroidBridge::UpdateAudioPlayingWindows(uint64_t aWindowId,
|
||||
bool aPlaying)
|
||||
nsAndroidBridge::UpdateAudioPlayingWindows(bool aPlaying)
|
||||
{
|
||||
// Request audio focus for the first audio playing window and abandon focus
|
||||
// for the last audio playing window.
|
||||
if (aPlaying && !mAudioPlayingWindows.Contains(aWindowId)) {
|
||||
mAudioPlayingWindows.AppendElement(aWindowId);
|
||||
if (mAudioPlayingWindows.Length() == 1) {
|
||||
ALOG_BRIDGE("nsAndroidBridge, request audio focus.");
|
||||
AudioFocusAgent::NotifyStartedPlaying();
|
||||
}
|
||||
} else if (!aPlaying && mAudioPlayingWindows.Contains(aWindowId)) {
|
||||
mAudioPlayingWindows.RemoveElement(aWindowId);
|
||||
if (mAudioPlayingWindows.Length() == 0) {
|
||||
ALOG_BRIDGE("nsAndroidBridge, abandon audio focus.");
|
||||
AudioFocusAgent::NotifyStoppedPlaying();
|
||||
}
|
||||
MOZ_ASSERT(mAudibleWindowsNum >= 0);
|
||||
if (aPlaying && mAudibleWindowsNum++ == 0) {
|
||||
ALOG_BRIDGE("nsAndroidBridge, request audio focus.");
|
||||
AudioFocusAgent::NotifyStartedPlaying();
|
||||
} else if (!aPlaying && --mAudibleWindowsNum == 0) {
|
||||
ALOG_BRIDGE("nsAndroidBridge, abandon audio focus.");
|
||||
AudioFocusAgent::NotifyStoppedPlaying();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -852,7 +836,7 @@ nsAndroidBridge::AddObservers()
|
|||
if (obs) {
|
||||
obs->AddObserver(this, "xpcom-shutdown", false);
|
||||
if (jni::IsFennec()) { // No AudioFocusAgent in non-Fennec environment.
|
||||
obs->AddObserver(this, "media-playback", false);
|
||||
obs->AddObserver(this, "audio-playback", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -864,7 +848,7 @@ nsAndroidBridge::RemoveObservers()
|
|||
if (obs) {
|
||||
obs->RemoveObserver(this, "xpcom-shutdown");
|
||||
if (jni::IsFennec()) { // No AudioFocusAgent in non-Fennec environment.
|
||||
obs->RemoveObserver(this, "media-playback");
|
||||
obs->RemoveObserver(this, "audio-playback");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче