Merge autoland to m-c, a=merge

This commit is contained in:
Phil Ringnalda 2017-01-25 20:37:29 -08:00
commit 7da3c9dcf4
181 changed files with 3595 additions and 900 deletions

View File

@ -905,7 +905,7 @@ function _loadURIWithFlags(browser, uri, params) {
let loadParams = {
uri,
triggeringPrincipal: triggeringPrincipal
? gSerializationHelper.serializePrincipal(triggeringPrincipal)
? gSerializationHelper.serializeToString(triggeringPrincipal)
: null,
flags,
referrer: referrer ? referrer.spec : null,

View File

@ -63,8 +63,8 @@ function checkNotification(panel, url) {
const INSTALL_FUNCTIONS = [
function installMozAM(url) {
ContentTask.spawn(gBrowser.selectedBrowser, url, function*(cUrl) {
content.wrappedJSObject.installMozAM(cUrl);
return ContentTask.spawn(gBrowser.selectedBrowser, url, function*(cUrl) {
yield content.wrappedJSObject.installMozAM(cUrl);
});
},
@ -72,6 +72,7 @@ const INSTALL_FUNCTIONS = [
ContentTask.spawn(gBrowser.selectedBrowser, url, function*(cUrl) {
content.wrappedJSObject.installTrigger(cUrl);
});
return Promise.resolve();
},
];
@ -117,17 +118,29 @@ add_task(function* () {
AddonManager.addInstallListener(listener);
});
installFn(url);
let installMethodPromise = installFn(url);
let panel = yield promisePopupNotificationShown("addon-webext-permissions");
checkNotification(panel, url);
if (cancel) {
panel.secondaryButton.click();
try {
yield installMethodPromise;
} catch (err) {}
} else {
// Look for post-install notification
let postInstallPromise = promisePopupNotificationShown("addon-installed");
panel.button.click();
// Press OK on the post-install notification
panel = yield postInstallPromise;
panel.button.click();
yield installMethodPromise;
}
let result = yield installPromise;
let addon = yield promiseGetAddonByID(ID);
if (cancel) {

View File

@ -7,9 +7,8 @@
<body>
<script type="text/javascript">
function installMozAM(url) {
return navigator.mozAddonManager.createInstall({url}).then(install => {
install.install();
});
return navigator.mozAddonManager.createInstall({url})
.then(install => install.install());
}
function installTrigger(url) {

View File

@ -130,8 +130,16 @@ class TestFirefoxRefresh(MarionetteTestCase):
}
}
});
let expectedTabs = new Set();
for (let url of expectedURLs) {
gBrowser.addTab(url);
expectedTabs.add(gBrowser.addTab(url));
}
// Close any other tabs that might be open:
let allTabs = Array.from(gBrowser.tabs);
for (let tab of allTabs) {
if (!expectedTabs.has(tab)) {
gBrowser.removeTab(tab);
}
}
""", script_args=[self._expectedURLs])
@ -275,8 +283,7 @@ class TestFirefoxRefresh(MarionetteTestCase):
}, false);
mm.loadFrameScript("data:application/javascript,(" + fs.toString() + ")()", true);
""")
self.assertSequenceEqual(tabURIs, ["about:blank"] + self._expectedURLs)
pass
self.assertSequenceEqual(tabURIs, self._expectedURLs)
def checkProfile(self, hasMigrated=False):
self.checkPassword()

View File

@ -330,7 +330,7 @@
<groupbox id="siteDataGroup" hidden="true">
<caption><label>&siteData.label;</label></caption>
<hbox align="center">
<hbox align="baseline">
<label id="totalSiteDataSize"></label>
<label id="siteDataLearnMoreLink" class="learnMore text-link" value="&siteDataLearnMoreLink.label;"></label>
<spacer flex="1" />

View File

@ -39,11 +39,12 @@
"unpack": true
},
{
"version": "makecab rev d2bc6797648b7a834782714a55d339d2fd4e58c8",
"algorithm": "sha512",
"visibility": "public",
"filename": "makecab.tar.bz2",
"unpack": true,
"digest": "da1f7685e5bc49a5ffbe5b4a3678ac7a58a0e125031726d30e2bacbbffa53d6efb9fd9f00d6dff5b54cff9412a103efa564c2af6f8fccc63082f6939181769f8",
"size": 296777
"digest": "196ac6a567c85559957dfe511c3d8654d23c94d5603259e19ccafe9d71e0e4ccee63ccc9a778f2699654b786cda54266108b7d4db543d01bb0b42545b4e6ec75",
"size": 297118
}
]

View File

@ -31,11 +31,12 @@
"unpack": true
},
{
"version": "makecab rev d2bc6797648b7a834782714a55d339d2fd4e58c8",
"algorithm": "sha512",
"visibility": "public",
"filename": "makecab.tar.bz2",
"unpack": true,
"digest": "da1f7685e5bc49a5ffbe5b4a3678ac7a58a0e125031726d30e2bacbbffa53d6efb9fd9f00d6dff5b54cff9412a103efa564c2af6f8fccc63082f6939181769f8",
"size": 296777
"digest": "196ac6a567c85559957dfe511c3d8654d23c94d5603259e19ccafe9d71e0e4ccee63ccc9a778f2699654b786cda54266108b7d4db543d01bb0b42545b4e6ec75",
"size": 297118
}
]

View File

@ -40,11 +40,12 @@
"unpack": true
},
{
"version": "makecab rev d2bc6797648b7a834782714a55d339d2fd4e58c8",
"algorithm": "sha512",
"visibility": "public",
"filename": "makecab.tar.bz2",
"unpack": true,
"digest": "da1f7685e5bc49a5ffbe5b4a3678ac7a58a0e125031726d30e2bacbbffa53d6efb9fd9f00d6dff5b54cff9412a103efa564c2af6f8fccc63082f6939181769f8",
"size": 296777
"digest": "196ac6a567c85559957dfe511c3d8654d23c94d5603259e19ccafe9d71e0e4ccee63ccc9a778f2699654b786cda54266108b7d4db543d01bb0b42545b4e6ec75",
"size": 297118
}
]

View File

@ -32,11 +32,12 @@
"unpack": true
},
{
"version": "makecab rev d2bc6797648b7a834782714a55d339d2fd4e58c8",
"algorithm": "sha512",
"visibility": "public",
"filename": "makecab.tar.bz2",
"unpack": true,
"digest": "da1f7685e5bc49a5ffbe5b4a3678ac7a58a0e125031726d30e2bacbbffa53d6efb9fd9f00d6dff5b54cff9412a103efa564c2af6f8fccc63082f6939181769f8",
"size": 296777
"digest": "196ac6a567c85559957dfe511c3d8654d23c94d5603259e19ccafe9d71e0e4ccee63ccc9a778f2699654b786cda54266108b7d4db543d01bb0b42545b4e6ec75",
"size": 297118
}
]

View File

@ -1,2 +0,0 @@
wc-reporter.label=Report Site Issue
wc-reporter.tooltip=Report a site compatibility issue

View File

@ -0,0 +1,10 @@
# 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/.
# LOCALIZATION NOTE(wc-reporter.label): This string will be used in the
# Firefox menu panel below its button. Localized length should be considered.
wc-reporter.label=Report Site Issue
# LOCALIZATION NOTE(wc-reporter.tooltip): A site compatibility issue is
# a website bug that exists in one browser (Firefox), but not another.
wc-reporter.tooltip=Report a site compatibility issue

View File

@ -5,4 +5,4 @@
[features/webcompat-reporter@mozilla.org] @AB_CD@.jar:
% locale webcompat-reporter @AB_CD@ %locale/@AB_CD@/
locale/@AB_CD@/ (en-US/*)
locale/@AB_CD@/webcompat.properties (%webcompat.properties)

View File

@ -7,7 +7,7 @@
DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
DEFINES['MOZ_APP_MAXVERSION'] = CONFIG['MOZ_APP_MAXVERSION']
DIRS += ['locale']
DIRS += ['locales']
FINAL_TARGET_FILES.features['webcompat-reporter@mozilla.org'] += [
'bootstrap.js'

View File

@ -107,7 +107,7 @@ endif
@$(MAKE) libs AB_CD=$* XPI_NAME=locale-$* PREF_DIR=$(PREF_DIR)
@$(MAKE) -C $(DEPTH)/$(MOZ_BRANDING_DIRECTORY)/locales AB_CD=$* XPI_NAME=locale-$*
ifdef NIGHTLY_BUILD
@$(MAKE) -C ../extensions/webcompat-reporter/locale AB_CD=$* XPI_NAME=locale-$*
@$(MAKE) -C ../extensions/webcompat-reporter/locales AB_CD=$* XPI_NAME=locale-$*
endif
repackage-win32-installer: WIN32_INSTALLER_OUT=$(ABS_DIST)/$(PKG_INST_PATH)$(PKG_INST_BASENAME).exe

View File

@ -8,6 +8,7 @@ def test(mod, path, entity = None):
if mod not in ("netwerk", "dom", "toolkit", "security/manager",
"devtools/client", "devtools/shared",
"browser",
"browser/extensions/webcompat-reporter",
"extensions/spellcheck",
"other-licenses/branding/firefox",
"browser/branding/official",

View File

@ -11,6 +11,7 @@ dirs = browser
other-licenses/branding/firefox
browser/branding/official
devtools/client
browser/extensions/webcompat-reporter
[includes]
# non-central apps might want to use %(topsrcdir)s here, or other vars

View File

@ -143,8 +143,12 @@ this.ExtensionsUI = {
this.updates.add(subject.wrappedJSObject);
this.emit("change");
} else if (topic == "webextension-install-notify") {
let {target, addon} = subject.wrappedJSObject;
this.showInstallNotification(target, addon);
let {target, addon, callback} = subject.wrappedJSObject;
this.showInstallNotification(target, addon).then(() => {
if (callback) {
callback();
}
});
}
},
@ -330,28 +334,32 @@ this.ExtensionsUI = {
let msg2 = bundle.getFormattedString("addonPostInstall.message2",
[addonLabel, addonIcon, toolbarIcon]);
let action = {
label: bundle.getString("addonPostInstall.okay.label"),
accessKey: bundle.getString("addonPostInstall.okay.key"),
callback: () => {},
};
return new Promise(resolve => {
let action = {
label: bundle.getString("addonPostInstall.okay.label"),
accessKey: bundle.getString("addonPostInstall.okay.key"),
callback: resolve,
};
let options = {
hideClose: true,
popupIconURL: addon.iconURL || DEFAULT_EXTENSION_ICON,
eventCallback(topic) {
if (topic == "showing") {
let doc = this.browser.ownerDocument;
doc.getElementById("addon-installed-notification-header")
.innerHTML = msg1;
doc.getElementById("addon-installed-notification-message")
.innerHTML = msg2;
let options = {
hideClose: true,
popupIconURL: addon.iconURL || DEFAULT_EXTENSION_ICON,
eventCallback(topic) {
if (topic == "showing") {
let doc = this.browser.ownerDocument;
doc.getElementById("addon-installed-notification-header")
.innerHTML = msg1;
doc.getElementById("addon-installed-notification-message")
.innerHTML = msg2;
} else if (topic == "dismissed") {
resolve();
}
}
}
};
};
popups.show(target, "addon-installed", "", "addons-notification-icon",
action, null, options);
popups.show(target, "addon-installed", "", "addons-notification-icon",
action, null, options);
});
},
};

View File

@ -44,7 +44,7 @@ treecol {
}
.learnMore {
margin-inline-start: 1.5em;
margin-inline-start: 10px;
font-weight: normal;
white-space: nowrap;
}

View File

@ -6,6 +6,8 @@
<style>
div {
animation: wow 100s forwards;
/* Add a border here to avoid layout warnings in Linux debug builds: Bug 1329784 */
border: 1px solid transparent;
}
@keyframes wow {
0% {

View File

@ -6,6 +6,8 @@
.ball {
width: 80px;
height: 80px;
/* Add a border here to avoid layout warnings in Linux debug builds: Bug 1329784 */
border: 1px solid transparent;
border-radius: 50%;
}

View File

@ -6,6 +6,8 @@
.ball {
width: 80px;
height: 80px;
/* Add a border here to avoid layout warnings in Linux debug builds: Bug 1329784 */
border: 1px solid transparent;
border-radius: 50%;
background: #f06;

View File

@ -13,6 +13,7 @@
#include "mozilla/AutoRestore.h"
#include "mozilla/AsyncEventDispatcher.h" // For AsyncEventDispatcher
#include "mozilla/Maybe.h" // For Maybe
#include "mozilla/AnimationRule.h" // For AnimationRule
#include "nsAnimationManager.h" // For CSSAnimation
#include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
#include "nsIDocument.h" // For nsIDocument
@ -916,7 +917,7 @@ Animation::HasLowerCompositeOrderThan(const Animation& aOther) const
}
void
Animation::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
Animation::ComposeStyle(AnimationRule& aStyleRule,
const nsCSSPropertyIDSet& aPropertiesToSkip)
{
if (!mEffect) {

View File

@ -40,7 +40,7 @@ class nsIFrame;
namespace mozilla {
class AnimValuesStyleRule;
struct AnimationRule;
namespace dom {
@ -317,7 +317,7 @@ public:
* Any properties contained in |aPropertiesToSkip| will not be added or
* updated in |aStyleRule|.
*/
void ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
void ComposeStyle(AnimationRule& aStyleRule,
const nsCSSPropertyIDSet& aPropertiesToSkip);
void NotifyEffectTimingUpdated();

View File

@ -0,0 +1,24 @@
/* -*- 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_AnimationRule_h
#define mozilla_AnimationRule_h
#include "AnimValuesStyleRule.h"
#include "ServoAnimationRule.h"
namespace mozilla {
// A wrapper for animation rules.
struct AnimationRule
{
RefPtr<AnimValuesStyleRule> mGecko;
RefPtr<ServoAnimationRule> mServo;
};
} // namespace mozilla
#endif // mozilla_AnimationRule_h

View File

@ -64,12 +64,12 @@ struct ComputedTiming
}
enum class AnimationPhase {
Null, // Not sampled (null sample time)
Idle, // Not sampled (null sample time)
Before, // Sampled prior to the start of the active interval
Active, // Sampled within the active interval
After // Sampled after (or at) the end of the active interval
};
AnimationPhase mPhase = AnimationPhase::Null;
AnimationPhase mPhase = AnimationPhase::Idle;
ComputedTimingFunction::BeforeFlag mBeforeFlag =
ComputedTimingFunction::BeforeFlag::Unset;

View File

@ -93,7 +93,7 @@ DocumentTimeline::GetCurrentTimeStamp() const
// If we don't have a refresh driver and we've never had one use the
// timeline's zero time.
if (result.IsNull()) {
RefPtr<nsDOMNavigationTiming> timing = mDocument->GetNavigationTiming();
nsDOMNavigationTiming* timing = mDocument->GetNavigationTiming();
if (timing) {
result = timing->GetNavigationStartTimeStamp();
// Also, let this time represent the current refresh time. This way
@ -118,7 +118,7 @@ DocumentTimeline::ToTimelineTime(const TimeStamp& aTimeStamp) const
return result;
}
RefPtr<nsDOMNavigationTiming> timing = mDocument->GetNavigationTiming();
nsDOMNavigationTiming* timing = mDocument->GetNavigationTiming();
if (MOZ_UNLIKELY(!timing)) {
return result;
}

View File

@ -273,6 +273,8 @@ EffectCompositor::RequestRestyle(dom::Element* aElement,
}
if (aRestyleType == RestyleType::Layer) {
// FIXME: we call RequestRestyle for both stylo and gecko, so we
// should fix this after supporting animations on the compositor.
// Prompt layers to re-sync their animations.
if (mPresContext->RestyleManager()->IsServo()) {
NS_ERROR("stylo: Servo-backed style system should not be using "
@ -305,6 +307,12 @@ EffectCompositor::PostRestyleForAnimation(dom::Element* aElement,
nsRestyleHint hint = aCascadeLevel == CascadeLevel::Transitions ?
eRestyle_CSSTransitions :
eRestyle_CSSAnimations;
// FIXME: stylo only supports Self and Subtree hints now, so we override it
// for stylo.
if (mPresContext->StyleSet()->IsServo()) {
hint = eRestyle_Self | eRestyle_Subtree;
}
mPresContext->PresShell()->RestyleForAnimation(element, hint);
}
@ -420,7 +428,82 @@ EffectCompositor::GetAnimationRule(dom::Element* aElement,
return nullptr;
}
return effectSet->AnimationRule(aCascadeLevel);
return effectSet->AnimationRule(aCascadeLevel).mGecko;
}
namespace {
class EffectCompositeOrderComparator {
public:
bool Equals(const KeyframeEffectReadOnly* a,
const KeyframeEffectReadOnly* b) const
{
return a == b;
}
bool LessThan(const KeyframeEffectReadOnly* a,
const KeyframeEffectReadOnly* b) const
{
MOZ_ASSERT(a->GetAnimation() && b->GetAnimation());
MOZ_ASSERT(
Equals(a, b) ||
a->GetAnimation()->HasLowerCompositeOrderThan(*b->GetAnimation()) !=
b->GetAnimation()->HasLowerCompositeOrderThan(*a->GetAnimation()));
return a->GetAnimation()->HasLowerCompositeOrderThan(*b->GetAnimation());
}
};
}
ServoAnimationRule*
EffectCompositor::GetServoAnimationRule(const dom::Element* aElement,
CSSPseudoElementType aPseudoType,
CascadeLevel aCascadeLevel)
{
if (!mPresContext || !mPresContext->IsDynamic()) {
// For print or print preview, ignore animations.
return nullptr;
}
EffectSet* effectSet = EffectSet::GetEffectSet(aElement, aPseudoType);
if (!effectSet) {
return nullptr;
}
// Get a list of effects sorted by composite order.
nsTArray<KeyframeEffectReadOnly*> sortedEffectList(effectSet->Count());
for (KeyframeEffectReadOnly* effect : *effectSet) {
sortedEffectList.AppendElement(effect);
}
sortedEffectList.Sort(EffectCompositeOrderComparator());
AnimationRule& animRule = effectSet->AnimationRule(aCascadeLevel);
animRule.mServo = nullptr;
// If multiple animations affect the same property, animations with higher
// composite order (priority) override or add or animations with lower
// priority.
// stylo: we don't support animations on compositor now, so propertiesToSkip
// is an empty set.
const nsCSSPropertyIDSet propertiesToSkip;
for (KeyframeEffectReadOnly* effect : sortedEffectList) {
effect->GetAnimation()->ComposeStyle(animRule, propertiesToSkip);
}
MOZ_ASSERT(effectSet == EffectSet::GetEffectSet(aElement, aPseudoType),
"EffectSet should not change while composing style");
effectSet->UpdateAnimationRuleRefreshTime(
aCascadeLevel, mPresContext->RefreshDriver()->MostRecentRefresh());
return animRule.mServo;
}
void
EffectCompositor::ClearElementsToRestyle()
{
MOZ_ASSERT(NS_IsMainThread());
const auto iterEnd = mElementsToRestyle.end();
for (auto iter = mElementsToRestyle.begin(); iter != iterEnd; ++iter) {
iter->Clear();
}
}
/* static */ dom::Element*
@ -591,28 +674,6 @@ EffectCompositor::MaybeUpdateCascadeResults(Element* aElement,
MOZ_ASSERT(!effects->CascadeNeedsUpdate(), "Failed to update cascade state");
}
namespace {
class EffectCompositeOrderComparator {
public:
bool Equals(const KeyframeEffectReadOnly* a,
const KeyframeEffectReadOnly* b) const
{
return a == b;
}
bool LessThan(const KeyframeEffectReadOnly* a,
const KeyframeEffectReadOnly* b) const
{
MOZ_ASSERT(a->GetAnimation() && b->GetAnimation());
MOZ_ASSERT(
Equals(a, b) ||
a->GetAnimation()->HasLowerCompositeOrderThan(*b->GetAnimation()) !=
b->GetAnimation()->HasLowerCompositeOrderThan(*a->GetAnimation()));
return a->GetAnimation()->HasLowerCompositeOrderThan(*b->GetAnimation());
}
};
}
/* static */ void
EffectCompositor::UpdateCascadeResults(Element* aElement,
CSSPseudoElementType aPseudoType,
@ -685,9 +746,8 @@ EffectCompositor::ComposeAnimationRule(dom::Element* aElement,
}
sortedEffectList.Sort(EffectCompositeOrderComparator());
RefPtr<AnimValuesStyleRule>& animationRule =
effects->AnimationRule(aCascadeLevel);
animationRule = nullptr;
AnimationRule& animRule = effects->AnimationRule(aCascadeLevel);
animRule.mGecko = nullptr;
// If multiple animations affect the same property, animations with higher
// composite order (priority) override or add or animations with lower
@ -697,7 +757,7 @@ EffectCompositor::ComposeAnimationRule(dom::Element* aElement,
? effects->PropertiesForAnimationsLevel().Invert()
: effects->PropertiesForAnimationsLevel();
for (KeyframeEffectReadOnly* effect : sortedEffectList) {
effect->GetAnimation()->ComposeStyle(animationRule, propertiesToSkip);
effect->GetAnimation()->ComposeStyle(animRule, propertiesToSkip);
}
MOZ_ASSERT(effects == EffectSet::GetEffectSet(aElement, aPseudoType),

View File

@ -29,6 +29,7 @@ namespace mozilla {
class EffectSet;
class RestyleTracker;
class StyleAnimationValue;
class ServoAnimationRule;
struct AnimationPerformanceWarning;
struct AnimationProperty;
struct NonOwningAnimationTarget;
@ -59,12 +60,12 @@ public:
}
// Animations can be applied at two different levels in the CSS cascade:
enum class CascadeLevel {
enum class CascadeLevel : uint32_t {
// The animations sheet (CSS animations, script-generated animations,
// and CSS transitions that are no longer tied to CSS markup)
Animations,
Animations = 0,
// The transitions sheet (CSS transitions that are tied to CSS markup)
Transitions
Transitions = 1
};
// We don't define this as part of CascadeLevel as then we'd have to add
// explicit checks for the Count enum value everywhere CascadeLevel is used.
@ -150,6 +151,21 @@ public:
CascadeLevel aCascadeLevel,
nsStyleContext* aStyleContext);
// Get animation rule for stylo. This is an equivalent of GetAnimationRule
// and will be called from servo side. We need to be careful while doing any
// modification because it may case some thread-safe issues.
ServoAnimationRule* GetServoAnimationRule(const dom::Element* aElement,
CSSPseudoElementType aPseudoType,
CascadeLevel aCascadeLevel);
// Clear mElementsToRestyle hashtable. Unlike GetAnimationRule,
// in GetServoAnimationRule, we don't remove the entry of the composed
// animation, so we can prevent the thread-safe issues of dom::Element.
// Therefore, we need to call Clear mElementsToRestyle until we go back to
// Gecko side.
// FIXME: we shouldn't clear the animations on the compositor.
void ClearElementsToRestyle();
bool HasPendingStyleUpdates() const;
bool HasThrottledStyleUpdates() const;

View File

@ -39,7 +39,7 @@ EffectSet::Traverse(nsCycleCollectionTraversalCallback& aCallback)
}
/* static */ EffectSet*
EffectSet::GetEffectSet(dom::Element* aElement,
EffectSet::GetEffectSet(const dom::Element* aElement,
CSSPseudoElementType aPseudoType)
{
nsIAtom* propName = GetEffectSetPropertyAtom(aPseudoType);

View File

@ -7,7 +7,7 @@
#ifndef mozilla_EffectSet_h
#define mozilla_EffectSet_h
#include "mozilla/AnimValuesStyleRule.h"
#include "mozilla/AnimationRule.h" // For AnimationRule
#include "mozilla/DebugOnly.h"
#include "mozilla/EffectCompositor.h"
#include "mozilla/EnumeratedArray.h"
@ -57,7 +57,7 @@ public:
// Methods for supporting cycle-collection
void Traverse(nsCycleCollectionTraversalCallback& aCallback);
static EffectSet* GetEffectSet(dom::Element* aElement,
static EffectSet* GetEffectSet(const dom::Element* aElement,
CSSPseudoElementType aPseudoType);
static EffectSet* GetEffectSet(const nsIFrame* aFrame);
static EffectSet* GetOrCreateEffectSet(dom::Element* aElement,
@ -163,8 +163,8 @@ public:
size_t Count() const { return mEffects.Count(); }
RefPtr<AnimValuesStyleRule>& AnimationRule(EffectCompositor::CascadeLevel
aCascadeLevel)
struct AnimationRule&
AnimationRule(EffectCompositor::CascadeLevel aCascadeLevel)
{
return mAnimationRule[aCascadeLevel];
}
@ -232,7 +232,7 @@ private:
EnumeratedArray<EffectCompositor::CascadeLevel,
EffectCompositor::CascadeLevel(
EffectCompositor::kCascadeLevelCount),
RefPtr<AnimValuesStyleRule>> mAnimationRule;
mozilla::AnimationRule> mAnimationRule;
// A parallel array to mAnimationRule that records the refresh driver
// timestamp when the rule was last updated. This is used for certain

View File

@ -10,6 +10,7 @@
// For UnrestrictedDoubleOrKeyframeAnimationOptions;
#include "mozilla/dom/CSSPseudoElement.h"
#include "mozilla/dom/KeyframeEffectBinding.h"
#include "mozilla/AnimationRule.h"
#include "mozilla/AnimationUtils.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/EffectSet.h"
@ -464,7 +465,7 @@ KeyframeEffectReadOnly::EnsureBaseStylesForCompositor(
void
KeyframeEffectReadOnly::ComposeStyle(
RefPtr<AnimValuesStyleRule>& aStyleRule,
AnimationRule& aStyleRule,
const nsCSSPropertyIDSet& aPropertiesToSkip)
{
MOZ_DIAGNOSTIC_ASSERT(!mIsComposingStyle,
@ -496,6 +497,9 @@ KeyframeEffectReadOnly::ComposeStyle(
return;
}
nsPresContext* presContext = GetPresContext();
bool isServoBackend = presContext && presContext->StyleSet()->IsServo();
mNeedsBaseStyleSet.Empty();
for (size_t propIdx = 0, propEnd = mProperties.Length();
@ -531,72 +535,131 @@ KeyframeEffectReadOnly::ComposeStyle(
prop.mSegments.Length(),
"out of array bounds");
if (!aStyleRule) {
// Allocate the style rule now that we know we have animation data.
aStyleRule = new AnimValuesStyleRule();
}
// Bug 1333311 - We use two branches for Gecko and Stylo. However, it's
// better to remove the duplicated code.
if (isServoBackend) {
// Servo backend
StyleAnimationValue fromValue =
CompositeValue(prop.mProperty, aStyleRule,
segment->mFromValue,
segment->mFromComposite);
StyleAnimationValue toValue =
CompositeValue(prop.mProperty, aStyleRule,
segment->mToValue,
segment->mToComposite);
// Bug 1329878 - Stylo: Implement accumulate and addition on Servo
// AnimationValue.
RawServoAnimationValue* servoFromValue = segment->mServoFromValue;
RawServoAnimationValue* servoToValue = segment->mServoToValue;
// Iteration composition for accumulate
if (mEffectOptions.mIterationComposite ==
IterationCompositeOperation::Accumulate &&
computedTiming.mCurrentIteration > 0) {
const AnimationPropertySegment& lastSegment =
prop.mSegments.LastElement();
// FIXME: Bug 1293492: Add a utility function to calculate both of
// below StyleAnimationValues.
StyleAnimationValue lastValue = lastSegment.mToValue.IsNull()
? GetUnderlyingStyle(prop.mProperty, aStyleRule)
: lastSegment.mToValue;
fromValue =
StyleAnimationValue::Accumulate(prop.mProperty,
lastValue,
Move(fromValue),
computedTiming.mCurrentIteration);
toValue =
StyleAnimationValue::Accumulate(prop.mProperty,
lastValue,
Move(toValue),
computedTiming.mCurrentIteration);
}
// Special handling for zero-length segments
if (segment->mToKey == segment->mFromKey) {
if (computedTiming.mProgress.Value() < 0) {
aStyleRule->AddValue(prop.mProperty, Move(fromValue));
} else {
aStyleRule->AddValue(prop.mProperty, Move(toValue));
// For unsupported or non-animatable animation types, we get nullptrs.
if (!servoFromValue || !servoToValue) {
NS_ERROR("Compose style for unsupported or non-animatable property, "
"so get invalid RawServoAnimationValues");
continue;
}
continue;
}
double positionInSegment =
(computedTiming.mProgress.Value() - segment->mFromKey) /
(segment->mToKey - segment->mFromKey);
double valuePosition =
ComputedTimingFunction::GetPortion(segment->mTimingFunction,
positionInSegment,
computedTiming.mBeforeFlag);
if (!aStyleRule.mServo) {
// Allocate the style rule now that we know we have animation data.
aStyleRule.mServo = new ServoAnimationRule();
}
MOZ_ASSERT(IsFinite(valuePosition), "Position value should be finite");
StyleAnimationValue val;
if (StyleAnimationValue::Interpolate(prop.mProperty,
fromValue,
toValue,
valuePosition, val)) {
aStyleRule->AddValue(prop.mProperty, Move(val));
} else if (valuePosition < 0.5) {
aStyleRule->AddValue(prop.mProperty, Move(fromValue));
// Special handling for zero-length segments
if (segment->mToKey == segment->mFromKey) {
if (computedTiming.mProgress.Value() < 0) {
aStyleRule.mServo->AddValue(prop.mProperty, servoFromValue);
} else {
aStyleRule.mServo->AddValue(prop.mProperty, servoToValue);
}
continue;
}
double positionInSegment =
(computedTiming.mProgress.Value() - segment->mFromKey) /
(segment->mToKey - segment->mFromKey);
double valuePosition =
ComputedTimingFunction::GetPortion(segment->mTimingFunction,
positionInSegment,
computedTiming.mBeforeFlag);
MOZ_ASSERT(IsFinite(valuePosition), "Position value should be finite");
RefPtr<RawServoAnimationValue> interpolated =
Servo_AnimationValues_Interpolate(servoFromValue,
servoToValue,
valuePosition).Consume();
if (interpolated) {
aStyleRule.mServo->AddValue(prop.mProperty, interpolated);
} else if (valuePosition < 0.5) {
aStyleRule.mServo->AddValue(prop.mProperty, servoFromValue);
} else {
aStyleRule.mServo->AddValue(prop.mProperty, servoToValue);
}
} else {
aStyleRule->AddValue(prop.mProperty, Move(toValue));
// Gecko backend
if (!aStyleRule.mGecko) {
// Allocate the style rule now that we know we have animation data.
aStyleRule.mGecko = new AnimValuesStyleRule();
}
StyleAnimationValue fromValue =
CompositeValue(prop.mProperty, aStyleRule.mGecko,
segment->mFromValue,
segment->mFromComposite);
StyleAnimationValue toValue =
CompositeValue(prop.mProperty, aStyleRule.mGecko,
segment->mToValue,
segment->mToComposite);
// Iteration composition for accumulate
if (mEffectOptions.mIterationComposite ==
IterationCompositeOperation::Accumulate &&
computedTiming.mCurrentIteration > 0) {
const AnimationPropertySegment& lastSegment =
prop.mSegments.LastElement();
// FIXME: Bug 1293492: Add a utility function to calculate both of
// below StyleAnimationValues.
StyleAnimationValue lastValue = lastSegment.mToValue.IsNull()
? GetUnderlyingStyle(prop.mProperty, aStyleRule.mGecko)
: lastSegment.mToValue;
fromValue =
StyleAnimationValue::Accumulate(prop.mProperty,
lastValue,
Move(fromValue),
computedTiming.mCurrentIteration);
toValue =
StyleAnimationValue::Accumulate(prop.mProperty,
lastValue,
Move(toValue),
computedTiming.mCurrentIteration);
}
// Special handling for zero-length segments
if (segment->mToKey == segment->mFromKey) {
if (computedTiming.mProgress.Value() < 0) {
aStyleRule.mGecko->AddValue(prop.mProperty, Move(fromValue));
} else {
aStyleRule.mGecko->AddValue(prop.mProperty, Move(toValue));
}
continue;
}
double positionInSegment =
(computedTiming.mProgress.Value() - segment->mFromKey) /
(segment->mToKey - segment->mFromKey);
double valuePosition =
ComputedTimingFunction::GetPortion(segment->mTimingFunction,
positionInSegment,
computedTiming.mBeforeFlag);
MOZ_ASSERT(IsFinite(valuePosition), "Position value should be finite");
StyleAnimationValue val;
if (StyleAnimationValue::Interpolate(prop.mProperty,
fromValue,
toValue,
valuePosition, val)) {
aStyleRule.mGecko->AddValue(prop.mProperty, Move(val));
} else if (valuePosition < 0.5) {
aStyleRule.mGecko->AddValue(prop.mProperty, Move(fromValue));
} else {
aStyleRule.mGecko->AddValue(prop.mProperty, Move(toValue));
}
}
}

View File

@ -40,6 +40,7 @@ namespace mozilla {
class AnimValuesStyleRule;
enum class CSSPseudoElementType : uint8_t;
class ErrorResult;
struct AnimationRule;
struct TimingParams;
namespace dom {
@ -291,7 +292,7 @@ public:
// Updates |aStyleRule| with the animation values produced by this
// AnimationEffect for the current time except any properties contained
// in |aPropertiesToSkip|.
void ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
void ComposeStyle(AnimationRule& aStyleRule,
const nsCSSPropertyIDSet& aPropertiesToSkip);
// Composite |aValueToComposite| on |aUnderlyingValue| with

View File

@ -0,0 +1,32 @@
/* -*- 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 "ServoAnimationRule.h"
namespace mozilla {
void
ServoAnimationRule::AddValue(nsCSSPropertyID aProperty,
RawServoAnimationValue* aValue)
{
MOZ_ASSERT(aProperty != eCSSProperty_UNKNOWN,
"Unexpected css property");
mAnimationValues.Put(aProperty, aValue);
}
RawServoDeclarationBlockStrong
ServoAnimationRule::GetValues() const
{
// FIXME: Pass the hash table into the FFI directly.
nsTArray<const RawServoAnimationValue*> values(mAnimationValues.Count());
auto iter = mAnimationValues.ConstIter();
for (; !iter.Done(); iter.Next()) {
values.AppendElement(iter.Data());
}
return Servo_AnimationValues_Uncompute(&values);
}
} // namespace mozilla

View File

@ -0,0 +1,39 @@
/* -*- 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_ServoAnimationRule_h
#define mozilla_ServoAnimationRule_h
#include "nsCSSPropertyID.h"
#include "nsHashKeys.h" // For nsUint32HashKey
#include "nsRefPtrHashtable.h"
#include "ServoBindings.h"
namespace mozilla {
/**
* A rule for Stylo Animation Rule.
*/
class ServoAnimationRule
{
public:
ServoAnimationRule() = default;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ServoAnimationRule)
void AddValue(nsCSSPropertyID aProperty,
RawServoAnimationValue* aValue);
MOZ_MUST_USE RawServoDeclarationBlockStrong GetValues() const;
private:
~ServoAnimationRule() = default;
nsRefPtrHashtable<nsUint32HashKey, RawServoAnimationValue> mAnimationValues;
};
} // namespace mozilla
#endif // mozilla_ServoAnimationRule_h

View File

@ -22,6 +22,7 @@ EXPORTS.mozilla.dom += [
EXPORTS.mozilla += [
'AnimationComparator.h',
'AnimationPerformanceWarning.h',
'AnimationRule.h',
'AnimationTarget.h',
'AnimationUtils.h',
'AnimValuesStyleRule.h',
@ -33,6 +34,7 @@ EXPORTS.mozilla += [
'KeyframeUtils.h',
'PendingAnimationTracker.h',
'PseudoElementHashEntry.h',
'ServoAnimationRule.h',
'TimingParams.h',
]
@ -55,6 +57,7 @@ UNIFIED_SOURCES += [
'KeyframeEffectReadOnly.cpp',
'KeyframeUtils.cpp',
'PendingAnimationTracker.cpp',
'ServoAnimationRule.cpp',
'TimingParams.cpp',
]

View File

@ -6,17 +6,17 @@ asserts-if(stylo,3) pref(dom.animations-api.core.enabled,true) load 1216842-3.ht
asserts-if(stylo,3) pref(dom.animations-api.core.enabled,true) load 1216842-4.html # bug 1324691
asserts-if(stylo,4-10) pref(dom.animations-api.core.enabled,true) load 1216842-5.html # bug 1324693
asserts-if(stylo,4-10) pref(dom.animations-api.core.enabled,true) load 1216842-6.html # bug 1324693
asserts-if(stylo,3-10) pref(dom.animations-api.core.enabled,true) load 1272475-1.html # bug 1324693
asserts-if(stylo,4-10) pref(dom.animations-api.core.enabled,true) load 1272475-2.html # bug 1324693
skip-if(stylo) pref(dom.animations-api.core.enabled,true) load 1272475-1.html # bug 1324693 and bug 1332657
skip-if(stylo) pref(dom.animations-api.core.enabled,true) load 1272475-2.html # bug 1324693 and bug 1332657
asserts-if(stylo,5) pref(dom.animations-api.core.enabled,true) load 1278485-1.html # bug 1324691
asserts-if(stylo,31) pref(dom.animations-api.core.enabled,true) load 1277272-1.html # bug 1324694
asserts-if(stylo,2) pref(dom.animations-api.core.enabled,true) load 1290535-1.html # bug 1324690
pref(dom.animations-api.core.enabled,true) load 1304886-1.html
pref(dom.animations-api.core.enabled,true) load 1322382-1.html
skip-if(stylo) pref(dom.animations-api.core.enabled,true) load 1322291-1.html # bug 1311257
skip-if(stylo) pref(dom.animations-api.core.enabled,true) load 1322291-2.html # bug 1311257
asserts-if(stylo,0-5) pref(dom.animations-api.core.enabled,true) load 1323114-1.html # bug 1324690
asserts-if(stylo,0-5) pref(dom.animations-api.core.enabled,true) load 1323114-2.html # bug 1324690
skip-if(stylo) pref(dom.animations-api.core.enabled,true) load 1322291-2.html # bug 1311257 and bug 1311257
skip-if(stylo) pref(dom.animations-api.core.enabled,true) load 1323114-1.html # bug 1324690 and bug 1311257
skip-if(stylo) pref(dom.animations-api.core.enabled,true) load 1323114-2.html # bug 1324690
skip-if(stylo) pref(dom.animations-api.core.enabled,true) load 1325193-1.html # bug 1311257
skip-if(stylo) pref(dom.animations-api.core.enabled,true) load 1330190-1.html # bug 1311257
skip-if(stylo) pref(dom.animations-api.core.enabled,true) load 1330190-2.html # bug 1311257

View File

@ -2384,7 +2384,7 @@ InitializeLegacyNetscapeObject(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
}
bool
nsGlobalWindow::ComputeIsSecureContext(nsIDocument* aDocument)
nsGlobalWindow::ComputeIsSecureContext(nsIDocument* aDocument, SecureContextFlags aFlags)
{
MOZ_ASSERT(IsOuterWindow());
@ -2394,6 +2394,7 @@ nsGlobalWindow::ComputeIsSecureContext(nsIDocument* aDocument)
}
// Implement https://w3c.github.io/webappsec-secure-contexts/#settings-object
// With some modifications to allow for aFlags.
bool hadNonSecureContextCreator = false;
@ -2419,9 +2420,15 @@ nsGlobalWindow::ComputeIsSecureContext(nsIDocument* aDocument)
MOZ_ASSERT(parentWin ==
nsGlobalWindow::Cast(parentOuterWin->GetCurrentInnerWindow()),
"Creator window mismatch while setting Secure Context state");
hadNonSecureContextCreator = !parentWin->IsSecureContext();
if (aFlags != SecureContextFlags::eIgnoreOpener) {
hadNonSecureContextCreator = !parentWin->IsSecureContext();
} else {
hadNonSecureContextCreator = !parentWin->IsSecureContextIfOpenerIgnored();
}
} else if (mHadOriginalOpener) {
hadNonSecureContextCreator = !mOriginalOpenerWasSecureContext;
if (aFlags != SecureContextFlags::eIgnoreOpener) {
hadNonSecureContextCreator = !mOriginalOpenerWasSecureContext;
}
}
if (hadNonSecureContextCreator) {
@ -2726,6 +2733,8 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
NS_ASSERTION(NS_SUCCEEDED(rv) && newInnerGlobal &&
newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal,
"Failed to get script global");
newInnerWindow->mIsSecureContextIfOpenerIgnored =
ComputeIsSecureContext(aDocument, SecureContextFlags::eIgnoreOpener);
mCreatingInnerWindow = false;
createdInnerWindow = true;
@ -3867,6 +3876,12 @@ nsPIDOMWindowInner::IsSecureContext() const
return nsGlobalWindow::Cast(this)->IsSecureContext();
}
bool
nsPIDOMWindowInner::IsSecureContextIfOpenerIgnored() const
{
return nsGlobalWindow::Cast(this)->IsSecureContextIfOpenerIgnored();
}
void
nsPIDOMWindowInner::Suspend()
{
@ -13827,6 +13842,14 @@ nsGlobalWindow::IsSecureContext() const
return JS_GetIsSecureContext(js::GetObjectCompartment(GetWrapperPreserveColor()));
}
bool
nsGlobalWindow::IsSecureContextIfOpenerIgnored() const
{
MOZ_RELEASE_ASSERT(IsInnerWindow());
return mIsSecureContextIfOpenerIgnored;
}
already_AddRefed<External>
nsGlobalWindow::GetExternal(ErrorResult& aRv)
{

View File

@ -911,6 +911,7 @@ public:
// https://w3c.github.io/webappsec-secure-contexts/#dom-window-issecurecontext
bool IsSecureContext() const;
bool IsSecureContextIfOpenerIgnored() const;
void GetSidebar(mozilla::dom::OwningExternalOrWindowProxy& aResult,
mozilla::ErrorResult& aRv);
@ -1753,9 +1754,16 @@ private:
void DisconnectEventTargetObjects();
enum class SecureContextFlags {
eDefault,
eIgnoreOpener
};
// Called only on outer windows to compute the value that will be returned by
// IsSecureContext() for the inner window that corresponds to aDocument.
bool ComputeIsSecureContext(nsIDocument* aDocument);
bool ComputeIsSecureContext(nsIDocument* aDocument,
SecureContextFlags aFlags =
SecureContextFlags::eDefault);
// nsPIDOMWindow<T> should be able to see these helper methods.
friend class nsPIDOMWindow<mozIDOMWindowProxy>;
@ -1792,6 +1800,7 @@ protected:
bool mHavePendingClose : 1;
bool mHadOriginalOpener : 1;
bool mOriginalOpenerWasSecureContext : 1;
bool mIsSecureContextIfOpenerIgnored : 1;
bool mIsPopupSpam : 1;
// Indicates whether scripts are allowed to close this window.

View File

@ -851,6 +851,7 @@ public:
* Check whether this window is a secure context.
*/
bool IsSecureContext() const;
bool IsSecureContextIfOpenerIgnored() const;
// Calling suspend should prevent any asynchronous tasks from
// executing javascript for this window. This means setTimeout,

View File

@ -1037,11 +1037,18 @@ class RTCPeerConnection {
"Invalid candidate (both sdpMid and sdpMLineIndex are null).",
"TypeError");
}
return await this._chain(() => new Promise((resolve, reject) => {
this._onAddIceCandidateSuccess = resolve;
this._onAddIceCandidateError = reject;
this._impl.addIceCandidate(candidate, sdpMid || "", sdpMLineIndex);
}));
return await this._chain(() => {
if (!this.remoteDescription) {
throw new this._win.DOMException(
"setRemoteDescription needs to called before addIceCandidate",
"InvalidStateError");
}
return new Promise((resolve, reject) => {
this._onAddIceCandidateSuccess = resolve;
this._onAddIceCandidateError = reject;
this._impl.addIceCandidate(candidate, sdpMid || "", sdpMLineIndex);
});
});
}
addStream(stream) {

View File

@ -317,11 +317,13 @@ VideoTrackEncoder::AppendVideoSegment(const VideoSegment& aSegment)
// Adapt to the time before the first frame. This extends the first frame
// from [start, end] to [0, end], but it'll do for now.
CheckedInt64 diff = FramesToUsecs(nullDuration, mTrackRate);
MOZ_ASSERT(diff.isValid());
if (diff.isValid()) {
mLastChunk.mTimeStamp -= TimeDuration::FromMicroseconds(diff.value());
mLastChunk.mDuration += nullDuration;
if (!diff.isValid()) {
NS_ERROR("null duration overflow");
return NS_ERROR_DOM_MEDIA_OVERFLOW_ERR;
}
mLastChunk.mTimeStamp -= TimeDuration::FromMicroseconds(diff.value());
mLastChunk.mDuration += nullDuration;
}
MOZ_ASSERT(!mLastChunk.IsNull());
@ -357,25 +359,41 @@ VideoTrackEncoder::AppendVideoSegment(const VideoSegment& aSegment)
}
}
TimeDuration diff = chunk.mTimeStamp - mLastChunk.mTimeStamp;
if (diff <= TimeDuration::FromSeconds(0)) {
// The timestamp from mLastChunk is newer than from chunk.
// This means the durations reported from MediaStreamGraph for mLastChunk
// were larger than the timestamp diff - and durations were used to
// trigger the 1-second frame above. This could happen due to drift or
// underruns in the graph.
TRACK_LOG(LogLevel::Warning,
("[VideoTrackEncoder]: Underrun detected. Diff=%.5fs",
diff.ToSeconds()));
chunk.mTimeStamp = mLastChunk.mTimeStamp;
} else {
RefPtr<layers::Image> lastImage = mLastChunk.mFrame.GetImage();
TRACK_LOG(LogLevel::Verbose,
("[VideoTrackEncoder]: Appending video frame %p, duration=%.5f",
lastImage.get(), diff.ToSeconds()));
CheckedInt64 duration = UsecsToFrames(diff.ToMicroseconds(), mTrackRate);
MOZ_ASSERT(duration.isValid());
if (duration.isValid()) {
if (mStartOffset.IsNull()) {
mStartOffset = mLastChunk.mTimeStamp;
}
TimeDuration relativeTime = chunk.mTimeStamp - mStartOffset;
RefPtr<layers::Image> lastImage = mLastChunk.mFrame.GetImage();
TRACK_LOG(LogLevel::Verbose,
("[VideoTrackEncoder]: Appending video frame %p, at pos %.5fs",
lastImage.get(), relativeTime.ToSeconds()));
CheckedInt64 totalDuration =
UsecsToFrames(relativeTime.ToMicroseconds(), mTrackRate);
if (!totalDuration.isValid()) {
NS_ERROR("Duration overflow");
return NS_ERROR_DOM_MEDIA_OVERFLOW_ERR;
}
CheckedInt64 duration = totalDuration - mEncodedTicks;
if (!duration.isValid()) {
NS_ERROR("Duration overflow");
return NS_ERROR_DOM_MEDIA_OVERFLOW_ERR;
}
if (duration.isValid()) {
if (duration.value() <= 0) {
// The timestamp for mLastChunk is newer than for chunk.
// This means the durations reported from MediaStreamGraph for
// mLastChunk were larger than the timestamp diff - and durations were
// used to trigger the 1-second frame above. This could happen due to
// drift or underruns in the graph.
TRACK_LOG(LogLevel::Warning,
("[VideoTrackEncoder]: Underrun detected. Diff=%lld",
duration.value()));
chunk.mTimeStamp = mLastChunk.mTimeStamp;
} else {
mEncodedTicks += duration.value();
mRawSegment.AppendFrame(lastImage.forget(),
duration.value(),
mLastChunk.mFrame.GetIntrinsicSize(),

View File

@ -76,7 +76,7 @@ public:
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mCanceled = true;
mReentrantMonitor.NotifyAll();
NotifyEndOfStream();
}
virtual void SetBitrate(const uint32_t aBitrate) {}
@ -255,6 +255,7 @@ public:
, mDisplayWidth(0)
, mDisplayHeight(0)
, mTrackRate(aTrackRate)
, mEncodedTicks(0)
, mVideoBitrate(0)
{
mLastChunk.mDuration = 0;
@ -349,6 +350,18 @@ protected:
*/
VideoSegment mRawSegment;
/**
* The number of mTrackRate ticks we have passed to the encoder.
* Only accessed in AppendVideoSegment().
*/
StreamTime mEncodedTicks;
/**
* The time of the first real video frame passed to the encoder.
* Only accessed in AppendVideoSegment().
*/
TimeStamp mStartOffset;
uint32_t mVideoBitrate;
};

View File

@ -187,7 +187,7 @@ VP8TrackEncoder::GetMetadata()
return meta.forget();
}
bool
nsresult
VP8TrackEncoder::GetEncodedPartitions(EncodedFrameContainer& aData)
{
vpx_codec_iter_t iter = nullptr;
@ -219,15 +219,36 @@ VP8TrackEncoder::GetEncodedPartitions(EncodedFrameContainer& aData)
// Copy the encoded data to aData.
EncodedFrame* videoData = new EncodedFrame();
videoData->SetFrameType(frameType);
// Convert the timestamp and duration to Usecs.
CheckedInt64 timestamp = FramesToUsecs(pkt->data.frame.pts, mTrackRate);
if (timestamp.isValid()) {
videoData->SetTimeStamp((uint64_t)timestamp.value());
if (!timestamp.isValid()) {
NS_ERROR("Microsecond timestamp overflow");
return NS_ERROR_DOM_MEDIA_OVERFLOW_ERR;
}
CheckedInt64 duration = FramesToUsecs(pkt->data.frame.duration, mTrackRate);
if (duration.isValid()) {
videoData->SetDuration((uint64_t)duration.value());
videoData->SetTimeStamp((uint64_t)timestamp.value());
mExtractedDuration += pkt->data.frame.duration;
if (!mExtractedDuration.isValid()) {
NS_ERROR("Duration overflow");
return NS_ERROR_DOM_MEDIA_OVERFLOW_ERR;
}
CheckedInt64 totalDuration =
FramesToUsecs(mExtractedDuration.value(), mTrackRate);
if (!totalDuration.isValid()) {
NS_ERROR("Duration overflow");
return NS_ERROR_DOM_MEDIA_OVERFLOW_ERR;
}
CheckedInt64 duration = totalDuration - mExtractedDurationUs;
if (!duration.isValid()) {
NS_ERROR("Duration overflow");
return NS_ERROR_DOM_MEDIA_OVERFLOW_ERR;
}
mExtractedDurationUs = totalDuration;
videoData->SetDuration((uint64_t)duration.value());
videoData->SwapInFrameData(frameData);
VP8LOG(LogLevel::Verbose,
"GetEncodedPartitions TimeStamp %lld, Duration %lld, FrameType %d",
@ -236,7 +257,7 @@ VP8TrackEncoder::GetEncodedPartitions(EncodedFrameContainer& aData)
aData.AppendEncodedFrame(videoData);
}
return !!pkt;
return pkt ? NS_OK : NS_ERROR_NOT_AVAILABLE;
}
static bool isYUV420(const PlanarYCbCrImage::Data *aData)
@ -549,7 +570,8 @@ VP8TrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
return NS_ERROR_FAILURE;
}
// Get the encoded data from VP8 encoder.
GetEncodedPartitions(aData);
rv = GetEncodedPartitions(aData);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
} else {
// SKIP_FRAME
// Extend the duration of the last encoded data in aData
@ -557,11 +579,21 @@ VP8TrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
VP8LOG(LogLevel::Warning, "MediaRecorder lagging behind. Skipping a frame.");
RefPtr<EncodedFrame> last = aData.GetEncodedFrames().LastElement();
if (last) {
CheckedInt64 skippedDuration = FramesToUsecs(chunk.mDuration, mTrackRate);
if (skippedDuration.isValid() && skippedDuration.value() > 0) {
last->SetDuration(last->GetDuration() +
(static_cast<uint64_t>(skippedDuration.value())));
mExtractedDuration += chunk.mDuration;
if (!mExtractedDuration.isValid()) {
NS_ERROR("skipped duration overflow");
return NS_ERROR_DOM_MEDIA_OVERFLOW_ERR;
}
CheckedInt64 totalDuration = FramesToUsecs(mExtractedDuration.value(), mTrackRate);
CheckedInt64 skippedDuration = totalDuration - mExtractedDurationUs;
mExtractedDurationUs = totalDuration;
if (!skippedDuration.isValid()) {
NS_ERROR("skipped duration overflow");
return NS_ERROR_DOM_MEDIA_OVERFLOW_ERR;
}
last->SetDuration(last->GetDuration() +
(static_cast<uint64_t>(skippedDuration.value())));
}
}
@ -590,7 +622,7 @@ VP8TrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
0, 0, VPX_DL_REALTIME)) {
return NS_ERROR_FAILURE;
}
} while(GetEncodedPartitions(aData));
} while(NS_SUCCEEDED(GetEncodedPartitions(aData)));
}
return NS_OK ;

View File

@ -47,7 +47,7 @@ private:
// Get the encoded data from encoder to aData.
// Return value: false if the vpx_codec_get_cx_data returns null
// for EOS detection.
bool GetEncodedPartitions(EncodedFrameContainer& aData);
nsresult GetEncodedPartitions(EncodedFrameContainer& aData);
// Prepare the input data to the mVPXImageWrapper for encoding.
nsresult PrepareRawFrame(VideoChunk &aChunk);
@ -55,6 +55,12 @@ private:
// Encoded timestamp.
StreamTime mEncodedTimestamp;
// Total duration in mTrackRate extracted by GetEncodedPartitions().
CheckedInt64 mExtractedDuration;
// Total duration in microseconds extracted by GetEncodedPartitions().
CheckedInt64 mExtractedDurationUs;
// Muted frame, we only create it once.
RefPtr<layers::Image> mMuteFrame;

View File

@ -472,6 +472,58 @@ TEST(VP8VideoTrackEncoder, SkippedFrames)
EXPECT_EQ(hundredMillis, totalDuration);
}
// Test encoding a track with frames subject to rounding errors.
TEST(VP8VideoTrackEncoder, RoundingErrorFramesEncode)
{
// Initiate VP8 encoder
TestVP8TrackEncoder encoder;
InitParam param = {true, 640, 480};
encoder.TestInit(param);
YUVBufferGenerator generator;
generator.Init(mozilla::gfx::IntSize(640, 480));
TimeStamp now = TimeStamp::Now();
VideoSegment segment;
// Pass nine frames with timestamps not expressable in 90kHz sample rate,
// then one frame to make the total duration one second.
uint32_t usPerFrame = 99999; //99.999ms
for (uint32_t i = 0; i < 9; ++i) {
segment.AppendFrame(generator.GenerateI420Image(),
mozilla::StreamTime(9000), // 100ms
generator.GetSize(),
PRINCIPAL_HANDLE_NONE,
false,
now + TimeDuration::FromMicroseconds(i * usPerFrame));
}
// This last frame has timestamp start + 0.9s and duration 0.1s.
segment.AppendFrame(generator.GenerateI420Image(),
mozilla::StreamTime(9000), // 100ms
generator.GetSize(),
PRINCIPAL_HANDLE_NONE,
false,
now + TimeDuration::FromSeconds(0.9));
encoder.SetCurrentFrames(segment);
// End the track.
segment.Clear();
encoder.NotifyQueuedTrackChanges(nullptr, 0, 0, TrackEventCommand::TRACK_EVENT_ENDED, segment);
EncodedFrameContainer container;
ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
EXPECT_TRUE(encoder.IsEncodingComplete());
// Verify total duration being 1s.
uint64_t totalDuration = 0;
for (auto& frame : container.GetEncodedFrames()) {
totalDuration += frame->GetDuration();
}
const uint64_t oneSecond= PR_USEC_PER_SEC;
EXPECT_EQ(oneSecond, totalDuration);
}
// EOS test
TEST(VP8VideoTrackEncoder, EncodeComplete)
{

View File

@ -29,99 +29,96 @@ function runTest(test, token, bitrate) {
element.token = token;
element.src = test.name;
element.test = test;
element.stream = element.mozCaptureStreamUntilEnded();
var mediaRecorder = new MediaRecorder(element.stream , {videoBitsPerSecond: bitrate});
var onStopFired = false;
var onDataAvailableFired = false;
var encoded_size = 0;
mediaRecorder.onerror = function () {
ok(false, 'Unexpected onerror callback fired');
};
mediaRecorder.onwarning = function () {
ok(false, 'Unexpected onwarning callback fired');
};
// This handler verifies that only a single onstop event handler is fired.
mediaRecorder.onstop = function () {
if (onStopFired) {
ok(false, 'onstop unexpectedly fired more than once');
} else {
onStopFired = true;
// ondataavailable should always fire before onstop
if (onDataAvailableFired) {
ok(true, 'onstop fired after ondataavailable');
info("test " + test.name + " encoded@" + bitrate + "=" + encoded_size);
if (results[test.name]) {
var big, small, temp;
big = {};
big.bitrate = bitrate;
big.size = encoded_size;
small = results[test.name];
// Don't assume the order that these will finish in
if (results[test.name].bitrate > bitrate) {
temp = big;
big = small;
small = temp;
}
// Ensure there is a big enough difference in the encoded
// sizes
ok(small.size*1.25 < big.size,
test.name + ' encoded@' + big.bitrate + '=' + big.size +
' > encoded@' + small.bitrate + '=' + small.size);
manager.finished(token);
} else {
results[test.name] = {};
results[test.name].bitrate = bitrate;
results[test.name].size = encoded_size;
}
} else {
ok(false, 'onstop fired without an ondataavailable event first');
}
}
};
// This handler verifies that only a single ondataavailable event handler
// is fired with the blob generated having greater than zero size
// and a correct mime type.
mediaRecorder.ondataavailable = function (evt) {
if (onDataAvailableFired) {
ok(false, 'ondataavailable unexpectedly fired more than once');
} else {
onDataAvailableFired = true;
ok(evt instanceof BlobEvent,
'Events fired from ondataavailable should be BlobEvent');
is(evt.type, 'dataavailable',
'Event type should dataavailable');
ok(evt.data.size > 0,
'Blob data received should be greater than zero');
encoded_size = evt.data.size;
// onstop should not have fired before ondataavailable
if (onStopFired) {
ok(false, 'ondataavailable unexpectedly fired later than onstop');
manager.finished(token);
}
}
};
element.preload = "metadata";
element.onloadedmetadata = function () {
info("loadedmetadata");
const stream = element.mozCaptureStreamUntilEnded();
element.onloadedmetadata = null;
element.play();
const mediaRecorder = new MediaRecorder(stream, {videoBitsPerSecond: bitrate});
mediaRecorder.start();
is(mediaRecorder.state, 'recording',
'Media recorder should be recording');
is(mediaRecorder.stream, element.stream,
is(mediaRecorder.state, 'recording', 'Media recorder should be recording');
is(mediaRecorder.stream, stream,
'Media recorder stream = element stream at the start of recording');
element.play();
}
var onStopFired = false;
var onDataAvailableFired = false;
var encoded_size = 0;
mediaRecorder.onerror = function () {
ok(false, 'Unexpected onerror callback fired');
};
mediaRecorder.onwarning = function () {
ok(false, 'Unexpected onwarning callback fired');
};
// This handler verifies that only a single onstop event handler is fired.
mediaRecorder.onstop = function () {
if (onStopFired) {
ok(false, 'onstop unexpectedly fired more than once');
} else {
onStopFired = true;
// ondataavailable should always fire before onstop
if (onDataAvailableFired) {
ok(true, 'onstop fired after ondataavailable');
info("test " + test.name + " encoded@" + bitrate + "=" + encoded_size);
if (results[test.name]) {
var big, small, temp;
big = {};
big.bitrate = bitrate;
big.size = encoded_size;
small = results[test.name];
// Don't assume the order that these will finish in
if (results[test.name].bitrate > bitrate) {
temp = big;
big = small;
small = temp;
}
// Ensure there is a big enough difference in the encoded
// sizes
ok(small.size*1.25 < big.size,
test.name + ' encoded@' + big.bitrate + '=' + big.size +
' > encoded@' + small.bitrate + '=' + small.size);
manager.finished(token);
} else {
results[test.name] = {};
results[test.name].bitrate = bitrate;
results[test.name].size = encoded_size;
}
} else {
ok(false, 'onstop fired without an ondataavailable event first');
}
}
};
// This handler verifies that only a single ondataavailable event handler
// is fired with the blob generated having greater than zero size
// and a correct mime type.
mediaRecorder.ondataavailable = function (evt) {
if (onDataAvailableFired) {
ok(false, 'ondataavailable unexpectedly fired more than once');
} else {
onDataAvailableFired = true;
ok(evt instanceof BlobEvent,
'Events fired from ondataavailable should be BlobEvent');
is(evt.type, 'dataavailable',
'Event type should dataavailable');
ok(evt.data.size > 0,
'Blob data received should be greater than zero');
encoded_size = evt.data.size;
// onstop should not have fired before ondataavailable
if (onStopFired) {
ok(false, 'ondataavailable unexpectedly fired later than onstop');
manager.finished(token);
}
}
};
};
}
manager.runTests(gMediaRecorderVideoTests, startTest);

View File

@ -360,8 +360,11 @@ TCPSocketParent::FireStringDataEvent(const nsACString& aData, TCPReadyState aRea
void
TCPSocketParent::SendEvent(const nsAString& aType, CallbackData aData, TCPReadyState aReadyState)
{
mozilla::Unused << PTCPSocketParent::SendCallback(nsString(aType), aData,
static_cast<uint32_t>(aReadyState));
if (mIPCOpen) {
mozilla::Unused << PTCPSocketParent::SendCallback(nsString(aType),
aData,
static_cast<uint32_t>(aReadyState));
}
}
void

View File

@ -310,6 +310,7 @@ UDPSocketParent::ConnectInternal(const nsCString& aHost, const uint16_t& aPort)
UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, nsCString(aHost).get(), aPort));
PRNetAddr prAddr;
memset(&prAddr, 0, sizeof(prAddr));
PR_InitializeNetAddr(PR_IpAddrAny, aPort, &prAddr);
PRStatus status = PR_StringToNetAddr(aHost.BeginReading(), &prAddr);
if (status != PR_SUCCESS) {

View File

@ -514,3 +514,16 @@ dictionary IdleRequestOptions {
};
callback IdleRequestCallback = void (IdleDeadline deadline);
/**
* Similar to |isSecureContext|, but doesn't pay attention to whether the
* window's opener (if any) is a secure context or not.
*
* WARNING: Do not use this unless you are familiar with the issues that
* taking opener state into account is designed to address (or else you may
* introduce security issues). If in doubt, use |isSecureContext|. In
* particular do not use this to gate access to JavaScript APIs.
*/
partial interface Window {
[ChromeOnly] readonly attribute boolean isSecureContextIfOpenerIgnored;
};

View File

@ -1446,8 +1446,6 @@ gfxWindowsPlatform::RecordContentDeviceFailure(TelemetryDeviceCode aDevice)
void
gfxWindowsPlatform::InitializeDevices()
{
MOZ_ASSERT(!InSafeMode());
if (XRE_IsParentProcess()) {
// If we're the UI process, and the GPU process is enabled, then we don't
// initialize any DirectX devices. We do leave them enabled in gfxConfig

View File

@ -24,7 +24,7 @@ VRDisplayHost::VRDisplayHost(VRDeviceType aType)
{
MOZ_COUNT_CTOR(VRDisplayHost);
mDisplayInfo.mType = aType;
mDisplayInfo.mDisplayID = VRDisplayManager::AllocateDisplayID();
mDisplayInfo.mDisplayID = VRSystemManager::AllocateDisplayID();
mDisplayInfo.mIsPresenting = false;
for (int i = 0; i < kMaxLatencyFrames; i++) {
@ -149,7 +149,7 @@ VRControllerHost::VRControllerHost(VRDeviceType aType)
{
MOZ_COUNT_CTOR(VRControllerHost);
mControllerInfo.mType = aType;
mControllerInfo.mControllerID = VRDisplayManager::AllocateDisplayID();
mControllerInfo.mControllerID = VRSystemManager::AllocateDisplayID();
}
VRControllerHost::~VRControllerHost()

View File

@ -51,8 +51,7 @@ VRManager::VRManager()
MOZ_COUNT_CTOR(VRManager);
MOZ_ASSERT(sVRManagerSingleton == nullptr);
RefPtr<VRDisplayManager> mgr;
RefPtr<VRControllerManager> controllerMgr;
RefPtr<VRSystemManager> mgr;
/**
* We must add the VRDisplayManager's to mManagers in a careful order to
@ -70,7 +69,7 @@ VRManager::VRManager()
#if defined(XP_WIN)
// The Oculus runtime is supported only on Windows
mgr = VRDisplayManagerOculus::Create();
mgr = VRSystemManagerOculus::Create();
if (mgr) {
mManagers.AppendElement(mgr);
}
@ -78,17 +77,13 @@ VRManager::VRManager()
#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
// OpenVR is cross platform compatible
mgr = VRDisplayManagerOpenVR::Create();
mgr = VRSystemManagerOpenVR::Create();
if (mgr) {
mManagers.AppendElement(mgr);
controllerMgr = VRControllerManagerOpenVR::Create();
if (controllerMgr) {
mControllerManagers.AppendElement(controllerMgr);
}
}
// OSVR is cross platform compatible
mgr = VRDisplayManagerOSVR::Create();
mgr = VRSystemManagerOSVR::Create();
if (mgr) {
mManagers.AppendElement(mgr);
}
@ -111,14 +106,11 @@ void
VRManager::Destroy()
{
mVRDisplays.Clear();
mVRControllers.Clear();
for (uint32_t i = 0; i < mManagers.Length(); ++i) {
mManagers[i]->Destroy();
}
mVRControllers.Clear();
for (uint32_t i = 0; i < mControllerManagers.Length(); ++i) {
mControllerManagers[i]->Destroy();
}
mInitialized = false;
}
@ -129,9 +121,6 @@ VRManager::Init()
mManagers[i]->Init();
}
for (uint32_t i = 0; i < mControllerManagers.Length(); ++i) {
mControllerManagers[i]->Init();
}
mInitialized = true;
}
@ -209,8 +198,8 @@ VRManager::NotifyVsync(const TimeStamp& aVsyncTimestamp)
void
VRManager::NotifyVRVsync(const uint32_t& aDisplayID)
{
for (uint32_t i = 0; i < mControllerManagers.Length(); ++i) {
mControllerManagers[i]->HandleInput();
for (uint32_t i = 0; i < mManagers.Length(); ++i) {
mManagers[i]->HandleInput();
}
for (auto iter = mVRManagerParents.Iter(); !iter.Done(); iter.Next()) {
Unused << iter.Get()->GetKey()->SendNotifyVRVSync(aDisplayID);
@ -343,9 +332,9 @@ VRManager::RefreshVRControllers()
ScanForControllers();
for (uint32_t i = 0; i < mControllerManagers.Length()
for (uint32_t i = 0; i < mManagers.Length()
&& controllers.Length() == 0; ++i) {
mControllerManagers[i]->GetControllers(controllers);
mManagers[i]->GetControllers(controllers);
}
bool controllerInfoChanged = false;
@ -375,16 +364,16 @@ VRManager::RefreshVRControllers()
void
VRManager::ScanForControllers()
{
for (uint32_t i = 0; i < mControllerManagers.Length(); ++i) {
mControllerManagers[i]->ScanForDevices();
for (uint32_t i = 0; i < mManagers.Length(); ++i) {
mManagers[i]->ScanForControllers();
}
}
void
VRManager::RemoveControllers()
{
for (uint32_t i = 0; i < mControllerManagers.Length(); ++i) {
mControllerManagers[i]->RemoveDevices();
for (uint32_t i = 0; i < mManagers.Length(); ++i) {
mManagers[i]->RemoveControllers();
}
mVRControllers.Clear();
}

View File

@ -22,7 +22,6 @@ namespace gfx {
class VRLayerParent;
class VRManagerParent;
class VRDisplayHost;
class VRControllerManager;
class VRManager
{
@ -66,11 +65,8 @@ private:
typedef nsTHashtable<nsRefPtrHashKey<VRManagerParent>> VRManagerParentSet;
VRManagerParentSet mVRManagerParents;
typedef nsTArray<RefPtr<VRDisplayManager>> VRDisplayManagerArray;
VRDisplayManagerArray mManagers;
typedef nsTArray<RefPtr<VRControllerManager>> VRControllerManagerArray;
VRControllerManagerArray mControllerManagers;
typedef nsTArray<RefPtr<VRSystemManager>> VRSystemManagerArray;
VRSystemManagerArray mManagers;
typedef nsRefPtrHashtable<nsUint32HashKey, gfx::VRDisplayHost> VRDisplayHostHashMap;
VRDisplayHostHashMap mVRDisplays;

View File

@ -16,11 +16,10 @@
using namespace mozilla;
using namespace mozilla::gfx;
Atomic<uint32_t> VRDisplayManager::sDisplayBase(0);
Atomic<uint32_t> VRControllerManager::sControllerBase(0);
Atomic<uint32_t> VRSystemManager::sDisplayBase(0);
/* static */ uint32_t
VRDisplayManager::AllocateDisplayID()
VRSystemManager::AllocateDisplayID()
{
return ++sDisplayBase;
}
@ -59,15 +58,9 @@ VRFieldOfView::ConstructProjectionMatrix(float zNear, float zFar,
return mobj;
}
/* static */ uint32_t
VRControllerManager::AllocateControllerID()
{
return ++sControllerBase;
}
void
VRControllerManager::AddGamepad(const char* aID, dom::GamepadMappingType aMapping,
dom::GamepadHand aHand, uint32_t aNumButtons, uint32_t aNumAxes)
VRSystemManager::AddGamepad(const char* aID, dom::GamepadMappingType aMapping,
dom::GamepadHand aHand, uint32_t aNumButtons, uint32_t aNumAxes)
{
dom::GamepadAdded a(NS_ConvertUTF8toUTF16(nsDependentCString(aID)), mControllerCount,
aMapping, aHand, dom::GamepadServiceType::VR, aNumButtons,
@ -79,7 +72,7 @@ VRControllerManager::AddGamepad(const char* aID, dom::GamepadMappingType aMappin
}
void
VRControllerManager::RemoveGamepad(uint32_t aIndex)
VRSystemManager::RemoveGamepad(uint32_t aIndex)
{
dom::GamepadRemoved a(aIndex, dom::GamepadServiceType::VR);
@ -89,8 +82,8 @@ VRControllerManager::RemoveGamepad(uint32_t aIndex)
}
void
VRControllerManager::NewButtonEvent(uint32_t aIndex, uint32_t aButton,
bool aPressed)
VRSystemManager::NewButtonEvent(uint32_t aIndex, uint32_t aButton,
bool aPressed)
{
dom::GamepadButtonInformation a(aIndex, dom::GamepadServiceType::VR,
aButton, aPressed, aPressed ? 1.0L : 0.0L);
@ -101,8 +94,8 @@ VRControllerManager::NewButtonEvent(uint32_t aIndex, uint32_t aButton,
}
void
VRControllerManager::NewAxisMove(uint32_t aIndex, uint32_t aAxis,
double aValue)
VRSystemManager::NewAxisMove(uint32_t aIndex, uint32_t aAxis,
double aValue)
{
dom::GamepadAxisInformation a(aIndex, dom::GamepadServiceType::VR,
aAxis, aValue);
@ -113,8 +106,8 @@ VRControllerManager::NewAxisMove(uint32_t aIndex, uint32_t aAxis,
}
void
VRControllerManager::NewPoseState(uint32_t aIndex,
const dom::GamepadPoseState& aPose)
VRSystemManager::NewPoseState(uint32_t aIndex,
const dom::GamepadPoseState& aPose)
{
dom::GamepadPoseInformation a(aIndex, dom::GamepadServiceType::VR,
aPose);

View File

@ -196,7 +196,7 @@ struct VRHMDSensorState {
}
};
class VRDisplayManager {
class VRSystemManager {
public:
static uint32_t AllocateDisplayID();
@ -204,15 +204,36 @@ protected:
static Atomic<uint32_t> sDisplayBase;
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRDisplayManager)
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRSystemManager)
virtual bool Init() = 0;
virtual void Destroy() = 0;
virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) = 0;
virtual void HandleInput() = 0;
virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult) = 0;
virtual void ScanForControllers() = 0;
virtual void RemoveControllers() = 0;
void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed);
void NewAxisMove(uint32_t aIndex, uint32_t aAxis, double aValue);
void NewPoseState(uint32_t aIndex, const dom::GamepadPoseState& aPose);
void AddGamepad(const char* aID, dom::GamepadMappingType aMapping,
dom::GamepadHand aHand, uint32_t aNumButtons, uint32_t aNumAxes);
void RemoveGamepad(uint32_t aIndex);
protected:
VRDisplayManager() { }
virtual ~VRDisplayManager() { }
VRSystemManager() : mControllerCount(0) { }
virtual ~VRSystemManager() { }
uint32_t mControllerCount;
private:
virtual void HandleButtonPress(uint32_t aControllerIdx,
uint64_t aButtonPressed) = 0;
virtual void HandleAxisMove(uint32_t aControllerIdx, uint32_t aAxis,
float aValue) = 0;
virtual void HandlePoseTracking(uint32_t aControllerIdx,
const dom::GamepadPoseState& aPose,
VRControllerHost* aController) = 0;
};
struct VRControllerInfo
@ -245,42 +266,6 @@ struct VRControllerInfo
}
};
class VRControllerManager {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRControllerManager)
static uint32_t AllocateControllerID();
virtual bool Init() = 0;
virtual void Destroy() = 0;
virtual void HandleInput() = 0;
virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult) = 0;
virtual void ScanForDevices() = 0;
virtual void RemoveDevices() = 0;
void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed);
void NewAxisMove(uint32_t aIndex, uint32_t aAxis, double aValue);
void NewPoseState(uint32_t aIndex, const dom::GamepadPoseState& aPose);
void AddGamepad(const char* aID, dom::GamepadMappingType aMapping,
dom::GamepadHand aHand, uint32_t aNumButtons, uint32_t aNumAxes);
void RemoveGamepad(uint32_t aIndex);
protected:
VRControllerManager() : mInstalled(false), mControllerCount(0) {}
virtual ~VRControllerManager() {}
bool mInstalled;
uint32_t mControllerCount;
static Atomic<uint32_t> sControllerBase;
private:
virtual void HandleButtonPress(uint32_t aControllerIdx,
uint64_t aButtonPressed) = 0;
virtual void HandleAxisMove(uint32_t aControllerIdx, uint32_t aAxis,
float aValue) = 0;
virtual void HandlePoseTracking(uint32_t aControllerIdx,
const dom::GamepadPoseState& aPose,
VRControllerHost* aController) = 0;
};
} // namespace gfx
} // namespace mozilla

View File

@ -21,6 +21,9 @@
#include "gfxVROSVR.h"
#include "mozilla/dom/GamepadEventTypes.h"
#include "mozilla/dom/GamepadBinding.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
@ -28,6 +31,7 @@
using namespace mozilla::layers;
using namespace mozilla::gfx;
using namespace mozilla::gfx::impl;
using namespace mozilla::dom;
namespace {
// need to typedef functions that will be used in the code below
@ -349,8 +353,8 @@ VRDisplayOSVR::StopPresentation()
// XXX Add code to end VR Presentation
}
already_AddRefed<VRDisplayManagerOSVR>
VRDisplayManagerOSVR::Create()
already_AddRefed<VRSystemManagerOSVR>
VRSystemManagerOSVR::Create()
{
MOZ_ASSERT(NS_IsMainThread());
@ -360,12 +364,12 @@ VRDisplayManagerOSVR::Create()
if (!LoadOSVRRuntime()) {
return nullptr;
}
RefPtr<VRDisplayManagerOSVR> manager = new VRDisplayManagerOSVR();
RefPtr<VRSystemManagerOSVR> manager = new VRSystemManagerOSVR();
return manager.forget();
}
void
VRDisplayManagerOSVR::CheckOSVRStatus()
VRSystemManagerOSVR::CheckOSVRStatus()
{
if (mOSVRInitialized) {
return;
@ -389,7 +393,7 @@ VRDisplayManagerOSVR::CheckOSVRStatus()
}
void
VRDisplayManagerOSVR::InitializeClientContext()
VRSystemManagerOSVR::InitializeClientContext()
{
// already initialized
if (mClientContextInitialized) {
@ -418,7 +422,7 @@ VRDisplayManagerOSVR::InitializeClientContext()
}
void
VRDisplayManagerOSVR::InitializeInterface()
VRSystemManagerOSVR::InitializeInterface()
{
// already initialized
if (mInterfaceInitialized) {
@ -435,7 +439,7 @@ VRDisplayManagerOSVR::InitializeInterface()
}
void
VRDisplayManagerOSVR::InitializeDisplay()
VRSystemManagerOSVR::InitializeDisplay()
{
// display is fully configured
if (mDisplayConfigInitialized) {
@ -470,7 +474,7 @@ VRDisplayManagerOSVR::InitializeDisplay()
}
bool
VRDisplayManagerOSVR::Init()
VRSystemManagerOSVR::Init()
{
// OSVR server should be running in the background
@ -494,7 +498,7 @@ VRDisplayManagerOSVR::Init()
}
void
VRDisplayManagerOSVR::Destroy()
VRSystemManagerOSVR::Destroy()
{
if (mOSVRInitialized) {
MOZ_ASSERT(NS_GetCurrentThread() == mOSVRThread);
@ -512,7 +516,7 @@ VRDisplayManagerOSVR::Destroy()
}
void
VRDisplayManagerOSVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
VRSystemManagerOSVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
{
// make sure context, interface and display are initialized
CheckOSVRStatus();
@ -527,3 +531,42 @@ VRDisplayManagerOSVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
aHMDResult.AppendElement(mHMDInfo);
}
}
void
VRSystemManagerOSVR::HandleInput()
{
}
void
VRSystemManagerOSVR::HandleButtonPress(uint32_t aControllerIdx,
uint64_t aButtonPressed)
{
}
void
VRSystemManagerOSVR::HandleAxisMove(uint32_t aControllerIdx, uint32_t aAxis,
float aValue)
{
}
void
VRSystemManagerOSVR::HandlePoseTracking(uint32_t aControllerIdx,
const GamepadPoseState& aPose,
VRControllerHost* aController)
{
}
void
VRSystemManagerOSVR::GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult)
{
}
void
VRSystemManagerOSVR::ScanForControllers()
{
}
void
VRSystemManagerOSVR::RemoveControllers()
{
}

View File

@ -61,16 +61,21 @@ protected:
} // namespace impl
class VRDisplayManagerOSVR : public VRDisplayManager
class VRSystemManagerOSVR : public VRSystemManager
{
public:
static already_AddRefed<VRDisplayManagerOSVR> Create();
static already_AddRefed<VRSystemManagerOSVR> Create();
virtual bool Init() override;
virtual void Destroy() override;
virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) override;
virtual void HandleInput() override;
virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>&
aControllerResult) override;
virtual void ScanForControllers() override;
virtual void RemoveControllers() override;
protected:
VRDisplayManagerOSVR()
VRSystemManagerOSVR()
: mOSVRInitialized(false)
, mClientContextInitialized(false)
, mDisplayConfigInitialized(false)
@ -93,6 +98,13 @@ protected:
OSVR_DisplayConfig m_display;
private:
virtual void HandleButtonPress(uint32_t aControllerIdx,
uint64_t aButtonPressed) override;
virtual void HandleAxisMove(uint32_t aControllerIdx, uint32_t aAxis,
float aValue) override;
virtual void HandlePoseTracking(uint32_t aControllerIdx,
const dom::GamepadPoseState& aPose,
VRControllerHost* aController) override;
// check if all components are initialized
// and if not, it will try to initialize them
void CheckOSVRStatus();

View File

@ -29,6 +29,9 @@
#include "gfxVROculus.h"
#include "mozilla/dom/GamepadEventTypes.h"
#include "mozilla/dom/GamepadBinding.h"
/** XXX The DX11 objects and quad blitting could be encapsulated
* into a separate object if either Oculus starts supporting
* non-Windows platforms or the blit is needed by other HMD\
@ -49,6 +52,7 @@ using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::gfx::impl;
using namespace mozilla::layers;
using namespace mozilla::dom;
namespace {
@ -618,8 +622,8 @@ VRDisplayOculus::StopPresentation()
}
}
/*static*/ already_AddRefed<VRDisplayManagerOculus>
VRDisplayManagerOculus::Create()
/*static*/ already_AddRefed<VRSystemManagerOculus>
VRSystemManagerOculus::Create()
{
MOZ_ASSERT(NS_IsMainThread());
@ -632,12 +636,12 @@ VRDisplayManagerOculus::Create()
return nullptr;
}
RefPtr<VRDisplayManagerOculus> manager = new VRDisplayManagerOculus();
RefPtr<VRSystemManagerOculus> manager = new VRSystemManagerOculus();
return manager.forget();
}
bool
VRDisplayManagerOculus::Init()
VRSystemManagerOculus::Init()
{
if (!mOculusInitialized) {
nsIThread* thread = nullptr;
@ -662,7 +666,7 @@ VRDisplayManagerOculus::Init()
}
void
VRDisplayManagerOculus::Destroy()
VRSystemManagerOculus::Destroy()
{
if (mOculusInitialized) {
MOZ_ASSERT(NS_GetCurrentThread() == mOculusThread);
@ -676,7 +680,7 @@ VRDisplayManagerOculus::Destroy()
}
void
VRDisplayManagerOculus::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
VRSystemManagerOculus::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
{
if (!mOculusInitialized) {
return;
@ -695,6 +699,7 @@ VRDisplayManagerOculus::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
ovrGraphicsLuid luid;
ovrResult orv = ovr_Create(&session, &luid);
if (orv == ovrSuccess) {
mSession = session;
mHMDInfo = new VRDisplayOculus(session);
}
}
@ -704,6 +709,45 @@ VRDisplayManagerOculus::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
}
}
void
VRSystemManagerOculus::HandleInput()
{
}
void
VRSystemManagerOculus::HandleButtonPress(uint32_t aControllerIdx,
uint64_t aButtonPressed)
{
}
void
VRSystemManagerOculus::HandleAxisMove(uint32_t aControllerIdx, uint32_t aAxis,
float aValue)
{
}
void
VRSystemManagerOculus::HandlePoseTracking(uint32_t aControllerIdx,
const GamepadPoseState& aPose,
VRControllerHost* aController)
{
}
void
VRSystemManagerOculus::GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult)
{
}
void
VRSystemManagerOculus::ScanForControllers()
{
}
void
VRSystemManagerOculus::RemoveControllers()
{
}
already_AddRefed<CompositingRenderTargetD3D11>
VRDisplayOculus::GetNextRenderTarget()
{

View File

@ -88,21 +88,37 @@ protected:
} // namespace impl
class VRDisplayManagerOculus : public VRDisplayManager
class VRSystemManagerOculus : public VRSystemManager
{
public:
static already_AddRefed<VRDisplayManagerOculus> Create();
static already_AddRefed<VRSystemManagerOculus> Create();
virtual bool Init() override;
virtual void Destroy() override;
virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost> >& aHMDResult) override;
virtual void HandleInput() override;
virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>&
aControllerResult) override;
virtual void ScanForControllers() override;
virtual void RemoveControllers() override;
protected:
VRDisplayManagerOculus()
VRSystemManagerOculus()
: mOculusInitialized(false)
{ }
private:
virtual void HandleButtonPress(uint32_t aControllerIdx,
uint64_t aButtonPressed) override;
virtual void HandleAxisMove(uint32_t aControllerIdx, uint32_t aAxis,
float aValue) override;
virtual void HandlePoseTracking(uint32_t aControllerIdx,
const dom::GamepadPoseState& aPose,
VRControllerHost* aController) override;
RefPtr<impl::VRDisplayOculus> mHMDInfo;
bool mOculusInitialized;
RefPtr<nsIThread> mOculusThread;
ovrSession mSession;
bool mOculusInitialized;
};
} // namespace gfx

View File

@ -394,13 +394,13 @@ VRDisplayOpenVR::NotifyVSync()
mDisplayInfo.mIsConnected = vr_IsHmdPresent();
}
VRDisplayManagerOpenVR::VRDisplayManagerOpenVR()
VRSystemManagerOpenVR::VRSystemManagerOpenVR()
: mOpenVRInstalled(false)
{
}
/*static*/ already_AddRefed<VRDisplayManagerOpenVR>
VRDisplayManagerOpenVR::Create()
/*static*/ already_AddRefed<VRSystemManagerOpenVR>
VRSystemManagerOpenVR::Create()
{
MOZ_ASSERT(NS_IsMainThread());
@ -412,12 +412,12 @@ VRDisplayManagerOpenVR::Create()
return nullptr;
}
RefPtr<VRDisplayManagerOpenVR> manager = new VRDisplayManagerOpenVR();
RefPtr<VRSystemManagerOpenVR> manager = new VRSystemManagerOpenVR();
return manager.forget();
}
bool
VRDisplayManagerOpenVR::Init()
VRSystemManagerOpenVR::Init()
{
if (mOpenVRInstalled)
return true;
@ -430,18 +430,19 @@ VRDisplayManagerOpenVR::Init()
}
void
VRDisplayManagerOpenVR::Destroy()
VRSystemManagerOpenVR::Destroy()
{
if (mOpenVRInstalled) {
if (mOpenVRHMD) {
mOpenVRHMD = nullptr;
}
RemoveControllers();
mOpenVRInstalled = false;
}
}
void
VRDisplayManagerOpenVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
VRSystemManagerOpenVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
{
if (!mOpenVRInstalled) {
return;
@ -475,6 +476,7 @@ VRDisplayManagerOpenVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
return;
}
mVRSystem = system;
mOpenVRHMD = new VRDisplayOpenVR(system, chaperone, compositor);
}
@ -483,90 +485,8 @@ VRDisplayManagerOpenVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
}
}
VRControllerOpenVR::VRControllerOpenVR()
: VRControllerHost(VRDeviceType::OpenVR)
{
MOZ_COUNT_CTOR_INHERITED(VRControllerOpenVR, VRControllerHost);
mControllerInfo.mControllerName.AssignLiteral("OpenVR HMD");
mControllerInfo.mMappingType = GamepadMappingType::_empty;
mControllerInfo.mNumButtons = gNumOpenVRButtonMask;
mControllerInfo.mNumAxes = gNumOpenVRAxis;
}
VRControllerOpenVR::~VRControllerOpenVR()
{
MOZ_COUNT_DTOR_INHERITED(VRControllerOpenVR, VRControllerHost);
}
void
VRControllerOpenVR::SetTrackedIndex(uint32_t aTrackedIndex)
{
mTrackedIndex = aTrackedIndex;
}
uint32_t
VRControllerOpenVR::GetTrackedIndex()
{
return mTrackedIndex;
}
VRControllerManagerOpenVR::VRControllerManagerOpenVR()
: mOpenVRInstalled(false), mVRSystem(nullptr)
{
}
VRControllerManagerOpenVR::~VRControllerManagerOpenVR()
{
Destroy();
}
/*static*/ already_AddRefed<VRControllerManagerOpenVR>
VRControllerManagerOpenVR::Create()
{
if (!gfxPrefs::VREnabled() || !gfxPrefs::VROpenVREnabled()) {
return nullptr;
}
RefPtr<VRControllerManagerOpenVR> manager = new VRControllerManagerOpenVR();
return manager.forget();
}
bool
VRControllerManagerOpenVR::Init()
{
if (mOpenVRInstalled)
return true;
if (!vr_IsRuntimeInstalled())
return false;
// Loading the OpenVR Runtime
vr::EVRInitError err = vr::VRInitError_None;
vr_InitInternal(&err, vr::VRApplication_Scene);
if (err != vr::VRInitError_None) {
return false;
}
mVRSystem = (vr::IVRSystem *)vr_GetGenericInterface(vr::IVRSystem_Version, &err);
if ((err != vr::VRInitError_None) || !mVRSystem) {
vr_ShutdownInternal();
return false;
}
mOpenVRInstalled = true;
return true;
}
void
VRControllerManagerOpenVR::Destroy()
{
RemoveDevices();
mOpenVRInstalled = false;
}
void
VRControllerManagerOpenVR::HandleInput()
VRSystemManagerOpenVR::HandleInput()
{
RefPtr<impl::VRControllerOpenVR> controller;
vr::VRControllerState_t state;
@ -645,8 +565,8 @@ VRControllerManagerOpenVR::HandleInput()
}
void
VRControllerManagerOpenVR::HandleButtonPress(uint32_t aControllerIdx,
uint64_t aButtonPressed)
VRSystemManagerOpenVR::HandleButtonPress(uint32_t aControllerIdx,
uint64_t aButtonPressed)
{
uint64_t buttonMask = 0;
RefPtr<impl::VRControllerOpenVR> controller;
@ -672,8 +592,8 @@ VRControllerManagerOpenVR::HandleButtonPress(uint32_t aControllerIdx,
}
void
VRControllerManagerOpenVR::HandleAxisMove(uint32_t aControllerIdx, uint32_t aAxis,
float aValue)
VRSystemManagerOpenVR::HandleAxisMove(uint32_t aControllerIdx, uint32_t aAxis,
float aValue)
{
if (aValue != 0.0f) {
NewAxisMove(aControllerIdx, aAxis, aValue);
@ -681,9 +601,9 @@ VRControllerManagerOpenVR::HandleAxisMove(uint32_t aControllerIdx, uint32_t aAxi
}
void
VRControllerManagerOpenVR::HandlePoseTracking(uint32_t aControllerIdx,
const GamepadPoseState& aPose,
VRControllerHost* aController)
VRSystemManagerOpenVR::HandlePoseTracking(uint32_t aControllerIdx,
const GamepadPoseState& aPose,
VRControllerHost* aController)
{
if (aPose != aController->GetPose()) {
aController->SetPose(aPose);
@ -692,7 +612,7 @@ VRControllerManagerOpenVR::HandlePoseTracking(uint32_t aControllerIdx,
}
void
VRControllerManagerOpenVR::GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult)
VRSystemManagerOpenVR::GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult)
{
if (!mOpenVRInstalled) {
return;
@ -705,7 +625,7 @@ VRControllerManagerOpenVR::GetControllers(nsTArray<RefPtr<VRControllerHost>>& aC
}
void
VRControllerManagerOpenVR::ScanForDevices()
VRSystemManagerOpenVR::ScanForControllers()
{
if (!mVRSystem)
return;
@ -769,8 +689,35 @@ VRControllerManagerOpenVR::ScanForDevices()
}
void
VRControllerManagerOpenVR::RemoveDevices()
VRSystemManagerOpenVR::RemoveControllers()
{
mOpenVRController.Clear();
mControllerCount = 0;
}
}
VRControllerOpenVR::VRControllerOpenVR()
: VRControllerHost(VRDeviceType::OpenVR)
{
MOZ_COUNT_CTOR_INHERITED(VRControllerOpenVR, VRControllerHost);
mControllerInfo.mControllerName.AssignLiteral("OpenVR HMD");
mControllerInfo.mMappingType = GamepadMappingType::_empty;
mControllerInfo.mNumButtons = gNumOpenVRButtonMask;
mControllerInfo.mNumAxes = gNumOpenVRAxis;
}
VRControllerOpenVR::~VRControllerOpenVR()
{
MOZ_COUNT_DTOR_INHERITED(VRControllerOpenVR, VRControllerHost);
}
void
VRControllerOpenVR::SetTrackedIndex(uint32_t aTrackedIndex)
{
mTrackedIndex = aTrackedIndex;
}
uint32_t
VRControllerOpenVR::GetTrackedIndex()
{
return mTrackedIndex;
}

View File

@ -68,26 +68,6 @@ protected:
void UpdateStageParameters();
};
} // namespace impl
class VRDisplayManagerOpenVR : public VRDisplayManager
{
public:
static already_AddRefed<VRDisplayManagerOpenVR> Create();
virtual bool Init() override;
virtual void Destroy() override;
virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost> >& aHMDResult) override;
protected:
VRDisplayManagerOpenVR();
// there can only be one
RefPtr<impl::VRDisplayOpenVR> mOpenVRHMD;
bool mOpenVRInstalled;
};
namespace impl {
class VRControllerOpenVR : public VRControllerHost
{
public:
@ -104,23 +84,24 @@ protected:
} // namespace impl
class VRControllerManagerOpenVR : public VRControllerManager
class VRSystemManagerOpenVR : public VRSystemManager
{
public:
static already_AddRefed<VRControllerManagerOpenVR> Create();
static already_AddRefed<VRSystemManagerOpenVR> Create();
virtual bool Init() override;
virtual void Destroy() override;
virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost> >& aHMDResult) override;
virtual void HandleInput() override;
virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>&
aControllerResult) override;
virtual void ScanForDevices() override;
virtual void RemoveDevices() override;
virtual void ScanForControllers() override;
virtual void RemoveControllers() override;
protected:
VRSystemManagerOpenVR();
private:
VRControllerManagerOpenVR();
~VRControllerManagerOpenVR();
virtual void HandleButtonPress(uint32_t aControllerIdx,
uint64_t aButtonPressed) override;
virtual void HandleAxisMove(uint32_t aControllerIdx, uint32_t aAxis,
@ -129,9 +110,11 @@ private:
const dom::GamepadPoseState& aPose,
VRControllerHost* aController) override;
bool mOpenVRInstalled;
// there can only be one
RefPtr<impl::VRDisplayOpenVR> mOpenVRHMD;
nsTArray<RefPtr<impl::VRControllerOpenVR>> mOpenVRController;
vr::IVRSystem *mVRSystem;
bool mOpenVRInstalled;
};
} // namespace gfx

View File

@ -227,3 +227,28 @@ def ctypes_and_compile_environment(ctypes, compile_environment, _):
return ctypes and compile_environment
include('ffi.configure', when=ctypes_and_compile_environment)
# Support various fuzzing options
# ==============================================================
with only_when('--enable-compile-environment'):
js_option('--enable-fuzzing', help='Enable fuzzing support')
@depends('--enable-fuzzing')
def enable_fuzzing(value):
if value:
return True
@depends(enable_fuzzing,
try_compile(body='__AFL_COMPILER;',
check_msg='for AFL compiler',
when='--enable-fuzzing'))
def enable_libfuzzer(fuzzing, afl):
if fuzzing and not afl:
return True
set_config('FUZZING', enable_fuzzing)
set_define('FUZZING', enable_fuzzing)
set_config('LIBFUZZER', enable_libfuzzer)
set_define('LIBFUZZER', enable_libfuzzer)

View File

@ -316,6 +316,7 @@ ServoRestyleManager::ProcessPendingRestyles()
if (HasPendingRestyles()) {
mInStyleRefresh = true;
styleSet->StyleDocument();
PresContext()->EffectCompositor()->ClearElementsToRestyle();
// First do any queued-up frame creation. (see bugs 827239 and 997506).
//

View File

@ -77,4 +77,32 @@ ShapeUtils::ComputeCircleRadius(StyleBasicShape* const aBasicShape,
return r;
}
nsSize
ShapeUtils::ComputeEllipseRadii(StyleBasicShape* const aBasicShape,
const nsPoint& aCenter,
const nsRect& aRefBox)
{
const nsTArray<nsStyleCoord>& coords = aBasicShape->Coordinates();
MOZ_ASSERT(coords.Length() == 2, "wrong number of arguments");
nsSize radii;
if (coords[0].GetUnit() == eStyleUnit_Enumerated) {
const StyleShapeRadius radiusX = coords[0].GetEnumValue<StyleShapeRadius>();
radii.width = ComputeShapeRadius(radiusX, aCenter.x, aRefBox.x,
aRefBox.XMost());
} else {
radii.width = nsRuleNode::ComputeCoordPercentCalc(coords[0], aRefBox.width);
}
if (coords[1].GetUnit() == eStyleUnit_Enumerated) {
const StyleShapeRadius radiusY = coords[1].GetEnumValue<StyleShapeRadius>();
radii.height = ComputeShapeRadius(radiusY, aCenter.y, aRefBox.y,
aRefBox.YMost());
} else {
radii.height = nsRuleNode::ComputeCoordPercentCalc(coords[1], aRefBox.height);
}
return radii;
}
} // namespace mozilla

View File

@ -48,6 +48,15 @@ struct ShapeUtils final
static nscoord ComputeCircleRadius(
mozilla::StyleBasicShape* const aBasicShape,
const nsPoint& aCenter, const nsRect& aRefBox);
// Compute the radii for an ellipse.
// @param aCenter the center of the ellipse.
// @param aRefBox the reference box of the ellipse.
// @return The radii of the ellipse in app units. The width and height
// represent the x-axis and y-axis radii of the ellipse.
static nsSize ComputeEllipseRadii(
mozilla::StyleBasicShape* const aBasicShape,
const nsPoint& aCenter, const nsRect& aRefBox);
};
} // namespace mozilla

View File

@ -6785,7 +6785,7 @@ nsLayoutUtils::HasNonZeroCorner(const nsStyleCorners& aCorners)
return false;
}
// aCorner is a "full corner" value, i.e. NS_CORNER_TOP_LEFT etc
// aCorner is a "full corner" value, i.e. eCornerTopLeft etc.
static bool IsCornerAdjacentToSide(uint8_t aCorner, Side aSide)
{
static_assert((int)eSideTop == eCornerTopLeft, "Check for Full Corner");

View File

@ -1035,7 +1035,7 @@ public:
/**
* Return whether any part of aTestRect is inside of the rounded
* rectangle formed by aBounds and aRadii (which are indexed by the
* NS_CORNER_* constants in nsStyleConsts.h). This is precise.
* enum HalfCorner constants in gfx/2d/Types.h). This is precise.
*/
static bool RoundedRectIntersectsRect(const nsRect& aRoundedRect,
const nscoord aRadii[8],

View File

@ -618,8 +618,6 @@ nsFloatManager::BoxShapeInfo::LineRight(WritingMode aWM,
nsFloatManager::CircleShapeInfo::CircleShapeInfo(
StyleBasicShape* const aBasicShape,
nscoord aLineLeft,
nscoord aBlockStart,
const LogicalRect& aShapeBoxRect,
WritingMode aWM,
const nsSize& aContainerSize)
@ -631,40 +629,60 @@ nsFloatManager::CircleShapeInfo::CircleShapeInfo(
aShapeBoxRect.GetPhysicalRect(aWM, aContainerSize);
nsPoint physicalCenter =
ShapeUtils::ComputeCircleOrEllipseCenter(aBasicShape, physicalShapeBoxRect);
mRadius =
ShapeUtils::ComputeCircleRadius(aBasicShape, physicalCenter,
physicalShapeBoxRect);
// Convert the coordinate space back to the same as FloatInfo::mRect.
// mCenter.x is in the line-axis of the frame manager and mCenter.y are in
// the frame manager's real block-axis.
LogicalPoint logicalCenter(aWM, physicalCenter, aContainerSize);
mCenter = nsPoint(logicalCenter.LineRelative(aWM, aContainerSize) + aLineLeft,
logicalCenter.B(aWM) + aBlockStart);
nscoord radius = ShapeUtils::ComputeCircleRadius(aBasicShape, physicalCenter,
physicalShapeBoxRect);
mRadii = nsSize(radius, radius);
mCenter = ConvertPhysicalToLogical(aWM, physicalCenter, aContainerSize);
}
nscoord
nsFloatManager::CircleShapeInfo::LineLeft(WritingMode aWM,
const nscoord aBStart,
const nscoord aBEnd) const
/////////////////////////////////////////////////////////////////////////////
// EllipseShapeInfo
nsFloatManager::EllipseShapeInfo::EllipseShapeInfo(
StyleBasicShape* const aBasicShape,
const LogicalRect& aShapeBoxRect,
WritingMode aWM,
const nsSize& aContainerSize)
{
nscoord lineLeftDiff =
ComputeEllipseLineInterceptDiff(BStart(), BEnd(),
mRadius, mRadius, mRadius, mRadius,
aBStart, aBEnd);
return mCenter.x - mRadius + lineLeftDiff;
// Use physical coordinates to compute the center of the ellipse() since
// the <position> keywords such as 'left', 'top', etc. are physical.
// https://drafts.csswg.org/css-shapes-1/#funcdef-ellipse
nsRect physicalShapeBoxRect =
aShapeBoxRect.GetPhysicalRect(aWM, aContainerSize);
nsPoint physicalCenter =
ShapeUtils::ComputeCircleOrEllipseCenter(aBasicShape, physicalShapeBoxRect);
nsSize physicalRadii =
ShapeUtils::ComputeEllipseRadii(aBasicShape, physicalCenter,
physicalShapeBoxRect);
LogicalSize logicalRadii(aWM, physicalRadii);
mRadii = nsSize(logicalRadii.ISize(aWM), logicalRadii.BSize(aWM));
mCenter = ConvertPhysicalToLogical(aWM, physicalCenter, aContainerSize);
}
nscoord
nsFloatManager::CircleShapeInfo::LineRight(WritingMode aWM,
nsFloatManager::EllipseShapeInfo::LineLeft(WritingMode aWM,
const nscoord aBStart,
const nscoord aBEnd) const
{
nscoord lineLeftDiff =
ComputeEllipseLineInterceptDiff(BStart(), BEnd(),
mRadii.width, mRadii.height,
mRadii.width, mRadii.height,
aBStart, aBEnd);
return mCenter.x - mRadii.width + lineLeftDiff;
}
nscoord
nsFloatManager::EllipseShapeInfo::LineRight(WritingMode aWM,
const nscoord aBStart,
const nscoord aBEnd) const
{
nscoord lineRightDiff =
ComputeEllipseLineInterceptDiff(BStart(), BEnd(),
mRadius, mRadius, mRadius, mRadius,
mRadii.width, mRadii.height,
mRadii.width, mRadii.height,
aBStart, aBEnd);
return mCenter.x + mRadius - lineRightDiff;
return mCenter.x + mRadii.width - lineRightDiff;
}
/////////////////////////////////////////////////////////////////////////////
@ -719,20 +737,36 @@ nsFloatManager::FloatInfo::FloatInfo(nsIFrame* aFrame,
}
if (shapeOutside.GetType() == StyleShapeSourceType::Box) {
nsRect shapeBoxRect(rect.LineLeft(aWM, aContainerSize) + aLineLeft,
rect.BStart(aWM) + aBlockStart,
nsRect shapeBoxRect(rect.LineLeft(aWM, aContainerSize), rect.BStart(aWM),
rect.ISize(aWM), rect.BSize(aWM));
mShapeInfo = MakeUnique<BoxShapeInfo>(shapeBoxRect, mFrame);
} else if (shapeOutside.GetType() == StyleShapeSourceType::Shape) {
StyleBasicShape* const basicShape = shapeOutside.GetBasicShape();
if (basicShape->GetShapeType() == StyleBasicShapeType::Circle) {
mShapeInfo = MakeUnique<CircleShapeInfo>(basicShape, aLineLeft, aBlockStart,
rect, aWM, aContainerSize);
switch (basicShape->GetShapeType()) {
case StyleBasicShapeType::Polygon:
// Bug 1326409 - Implement the rendering of basic shape polygon()
// for CSS shape-outside.
break;
case StyleBasicShapeType::Circle:
mShapeInfo =
MakeUnique<CircleShapeInfo>(basicShape, rect, aWM, aContainerSize);
break;
case StyleBasicShapeType::Ellipse:
mShapeInfo =
MakeUnique<EllipseShapeInfo>(basicShape, rect, aWM, aContainerSize);
break;
case StyleBasicShapeType::Inset:
// Bug 1326407 - Implement the rendering of basic shape inset() for
// CSS shape-outside.
break;
}
} else {
MOZ_ASSERT_UNREACHABLE("Unknown StyleShapeSourceType!");
}
// Translate the shape to the same origin as nsFloatManager.
mShapeInfo->Translate(aLineLeft, aBlockStart);
}
#ifdef NS_BUILD_REFCNT_LOGGING
@ -835,6 +869,9 @@ nsFloatManager::FloatInfo::IsEmpty(ShapeType aShapeType) const
return mShapeInfo->IsEmpty();
}
/////////////////////////////////////////////////////////////////////////////
// ShapeInfo
/* static */ nscoord
nsFloatManager::ShapeInfo::ComputeEllipseLineInterceptDiff(
const nscoord aShapeBoxBStart, const nscoord aShapeBoxBEnd,
@ -915,6 +952,17 @@ nsFloatManager::ShapeInfo::XInterceptAtY(const nscoord aY,
return aRadiusX * std::sqrt(1 - (aY * aY) / double(aRadiusY * aRadiusY));
}
/* static */ nsPoint
nsFloatManager::ShapeInfo::ConvertPhysicalToLogical(
WritingMode aWM,
const nsPoint& aPoint,
const nsSize& aContainerSize)
{
LogicalPoint logicalPoint(aWM, aPoint, aContainerSize);
return nsPoint(logicalPoint.LineRelative(aWM, aContainerSize),
logicalPoint.B(aWM));
}
//----------------------------------------------------------------------
nsAutoFloatManager::~nsAutoFloatManager()

View File

@ -64,6 +64,12 @@ struct nsFlowAreaRect {
* passing in the writing mode of the block formatting context (BFC), i.e.
* the of BlockReflowInput's writing mode.
*
* nsFloatManager uses a special logical coordinate space with inline
* coordinates on the line-axis and block coordinates on the block-axis
* based on the writing mode of the block formatting context. All the
* physical types like nsRect, nsPoint, etc. use this coordinate space. See
* FloatInfo::mRect for an example.
*
* [1] https://drafts.csswg.org/css-writing-modes/#line-mappings
* [2] https://drafts.csswg.org/css-writing-modes/#logical-to-physical
*/
@ -107,7 +113,7 @@ public:
const mozilla::LogicalRect& aRegion,
const nsSize& aContainerSize);
// Structure that stores the current state of a frame manager for
// Structure that stores the current state of a float manager for
// Save/Restore purposes.
struct SavedState {
explicit SavedState() {}
@ -352,6 +358,9 @@ private:
virtual nscoord BEnd() const = 0;
virtual bool IsEmpty() const = 0;
// Translate the current origin by the specified offsets.
virtual void Translate(nscoord aLineLeft, nscoord aBlockStart) = 0;
protected:
// Compute the minimum line-axis difference between the bounding shape
// box and its rounded corner within the given band (block-axis region).
@ -369,6 +378,12 @@ private:
static nscoord XInterceptAtY(const nscoord aY, const nscoord aRadiusX,
const nscoord aRadiusY);
// Convert the coordinate space from physical to the logical space used
// in nsFloatManager, which is the same as FloatInfo::mRect.
static nsPoint ConvertPhysicalToLogical(mozilla::WritingMode aWM,
const nsPoint& aPoint,
const nsSize& aContainerSize);
};
// Implements shape-outside: <shape-box>.
@ -391,25 +406,28 @@ private:
nscoord BEnd() const override { return mShapeBoxRect.YMost(); }
bool IsEmpty() const override { return mShapeBoxRect.IsEmpty(); };
void Translate(nscoord aLineLeft, nscoord aBlockStart) override
{
mShapeBoxRect.MoveBy(aLineLeft, aBlockStart);
}
private:
// This is the reference box of css shape-outside if specified, which
// implements the <shape-box> value in the CSS Shapes Module Level 1.
// The coordinate space is the same as FloatInfo::mRect.
const nsRect mShapeBoxRect;
nsRect mShapeBoxRect;
// The frame of the float.
nsIFrame* const mFrame;
};
// Implements shape-outside: circle().
class CircleShapeInfo final : public ShapeInfo
// Implements shape-outside: ellipse().
class EllipseShapeInfo : public ShapeInfo
{
public:
CircleShapeInfo(mozilla::StyleBasicShape* const aBasicShape,
nscoord aLineLeft,
nscoord aBlockStart,
const mozilla::LogicalRect& aShapeBoxRect,
mozilla::WritingMode aWM,
const nsSize& aContainerSize);
EllipseShapeInfo(mozilla::StyleBasicShape* const aBasicShape,
const mozilla::LogicalRect& aShapeBoxRect,
mozilla::WritingMode aWM,
const nsSize& aContainerSize);
nscoord LineLeft(mozilla::WritingMode aWM,
const nscoord aBStart,
@ -417,16 +435,34 @@ private:
nscoord LineRight(mozilla::WritingMode aWM,
const nscoord aBStart,
const nscoord aBEnd) const override;
nscoord BStart() const override { return mCenter.y - mRadius; }
nscoord BEnd() const override { return mCenter.y + mRadius; }
bool IsEmpty() const override { return mRadius == 0; };
nscoord BStart() const override { return mCenter.y - mRadii.height; }
nscoord BEnd() const override { return mCenter.y + mRadii.height; }
bool IsEmpty() const override { return mRadii.IsEmpty(); };
private:
// The position of the center of the circle. The coordinate space is the
void Translate(nscoord aLineLeft, nscoord aBlockStart) override
{
mCenter.MoveBy(aLineLeft, aBlockStart);
}
protected:
EllipseShapeInfo() = default;
// The position of the center of the ellipse. The coordinate space is the
// same as FloatInfo::mRect.
nsPoint mCenter;
// The radius of the circle in app units.
nscoord mRadius;
// The radii of the ellipse in app units. The width and height represent
// the line-axis and block-axis radii of the ellipse.
nsSize mRadii;
};
// Implements shape-outside: circle().
class CircleShapeInfo final : public EllipseShapeInfo
{
public:
CircleShapeInfo(mozilla::StyleBasicShape* const aBasicShape,
const mozilla::LogicalRect& aShapeBoxRect,
mozilla::WritingMode aWM,
const nsSize& aContainerSize);
};
struct FloatInfo {
@ -465,10 +501,10 @@ private:
// NB! This is really a logical rect in a writing mode suitable for
// placing floats, which is not necessarily the actual writing mode
// either of the block which created the frame manager or the block
// that is calling the frame manager. The inline coordinates are in
// the line-relative axis of the frame manager and its block
// coordinates are in the frame manager's real block direction.
// either of the block which created the float manager or the block
// that is calling the float manager. The inline coordinates are in
// the line-relative axis of the float manager and its block
// coordinates are in the float manager's block direction.
nsRect mRect;
// Pointer to a concrete subclass of ShapeInfo or null, which means that
// there is no shape-outside.

View File

@ -1165,7 +1165,7 @@ public:
/**
* Get the size, in app units, of the border radii. It returns FALSE iff all
* returned radii == 0 (so no border radii), TRUE otherwise.
* For the aRadii indexes, use the NS_CORNER_* constants in nsStyleConsts.h
* For the aRadii indexes, use the enum HalfCorner constants in gfx/2d/Types.h
* If a side is skipped via aSkipSides, its corners are forced to 0.
*
* All corner radii are then adjusted so they do not require more
@ -1192,7 +1192,7 @@ public:
* padding box, out to outline box) by reducing radii or increasing
* nonzero radii as appropriate.
*
* Indices into aRadii are the NS_CORNER_* constants in nsStyleConsts.h
* Indices into aRadii are the enum HalfCorner constants in gfx/2d/Types.h
*
* Note that InsetBorderRadii is lossy, since it can turn nonzero
* radii into zero, and OutsetBorderRadii does not inflate zero radii.
@ -1204,8 +1204,8 @@ public:
/**
* Fill in border radii for this frame. Return whether any are nonzero.
* Indices into aRadii are the NS_CORNER_* constants in nsStyleConsts.h
* aSkipSides is a union of SIDE_BIT_LEFT/RIGHT/TOP/BOTTOM bits that says
* Indices into aRadii are the enum HalfCorner constants in gfx/2d/Types.h
* aSkipSides is a union of eSideBitsLeft/Right/Top/Bottom bits that says
* which side(s) to skip.
*
* Note: GetMarginBoxBorderRadii() and GetShapeBoxBorderRadii() work only

View File

@ -115,7 +115,7 @@ public:
}
gfx::Rect mRect;
// Indices into mRadii are the NS_CORNER_* constants in nsStyleConsts.h
// Indices into mRadii are the enum HalfCorner constants in gfx/2d/Types.h
gfxFloat mRadii[8];
private:

View File

@ -61,3 +61,25 @@ fails == shape-outside-border-box-border-radius-004.html shape-outside-border-bo
== shape-outside-circle-022.html shape-outside-circle-022-ref.html
== shape-outside-circle-023.html shape-outside-circle-023-ref.html
== shape-outside-circle-024.html shape-outside-circle-024-ref.html
# Basic shape: ellipse()
== shape-outside-ellipse-001.html shape-outside-ellipse-001-ref.html
== shape-outside-ellipse-002.html shape-outside-ellipse-002-ref.html
== shape-outside-ellipse-003.html shape-outside-ellipse-003-ref.html
== shape-outside-ellipse-004.html shape-outside-ellipse-004-ref.html
== shape-outside-ellipse-005.html shape-outside-ellipse-005-ref.html
== shape-outside-ellipse-006.html shape-outside-ellipse-006-ref.html
== shape-outside-ellipse-007.html shape-outside-ellipse-007-ref.html
== shape-outside-ellipse-008.html shape-outside-ellipse-008-ref.html
== shape-outside-ellipse-009.html shape-outside-ellipse-009-ref.html
== shape-outside-ellipse-010.html shape-outside-ellipse-009-ref.html
== shape-outside-ellipse-011.html shape-outside-ellipse-011-ref.html
== shape-outside-ellipse-012.html shape-outside-ellipse-011-ref.html
== shape-outside-ellipse-013.html shape-outside-ellipse-013-ref.html
== shape-outside-ellipse-014.html shape-outside-ellipse-014-ref.html
== shape-outside-ellipse-015.html shape-outside-ellipse-015-ref.html
== shape-outside-ellipse-016.html shape-outside-ellipse-016-ref.html
== shape-outside-ellipse-017.html shape-outside-ellipse-017-ref.html
== shape-outside-ellipse-018.html shape-outside-ellipse-018-ref.html
== shape-outside-ellipse-019.html shape-outside-ellipse-019-ref.html
== shape-outside-ellipse-020.html shape-outside-ellipse-020-ref.html

View File

@ -52,5 +52,5 @@
<div class="box" style="height: 36px;"></div>
<div class="box" style="height: 24px;"></div> <!-- Box at corner -->
<div class="longbox"></div> <!-- Saturate the margin space -->
</body>
</body>
</html>

View File

@ -43,5 +43,5 @@
<div class="box" style="height: 36px;"></div>
<div class="box" style="height: 36px;"></div>
<div class="box" style="height: 24px;"></div> <!-- Box at corner -->
</body>
</body>
</html>

View File

@ -53,5 +53,5 @@
<div class="box" style="height: 36px;"></div>
<div class="box" style="height: 24px;"></div> <!-- Box at corner -->
<div class="longbox"></div> <!-- Saturate the margin space -->
</body>
</body>
</html>

View File

@ -44,5 +44,5 @@
<div class="box" style="height: 36px;"></div>
<div class="box" style="height: 36px;"></div>
<div class="box" style="height: 24px;"></div> <!-- Box at corner -->
</body>
</body>
</html>

View File

@ -53,5 +53,5 @@
<div class="box" style="block-size: 36px;"></div>
<div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
<div class="longbox"></div> <!-- Saturate the margin space -->
</body>
</body>
</html>

View File

@ -54,5 +54,5 @@
<div class="box" style="block-size: 36px;"></div>
<div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
<div class="longbox"></div> <!-- Saturate the margin space -->
</body>
</body>
</html>

View File

@ -53,5 +53,5 @@
<div class="box" style="block-size: 36px;"></div>
<div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
<div class="longbox"></div> <!-- Saturate the margin space -->
</body>
</body>
</html>

View File

@ -54,5 +54,5 @@
<div class="box" style="block-size: 36px;"></div>
<div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
<div class="longbox"></div> <!-- Saturate the margin space -->
</body>
</body>
</html>

View File

@ -53,5 +53,5 @@
<div class="box" style="block-size: 36px;"></div>
<div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
<div class="longbox"></div> <!-- Saturate the margin space -->
</body>
</body>
</html>

View File

@ -54,5 +54,5 @@
<div class="box" style="block-size: 36px;"></div>
<div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
<div class="longbox"></div> <!-- Saturate the margin space -->
</body>
</body>
</html>

View File

@ -53,5 +53,5 @@
<div class="box" style="block-size: 36px;"></div>
<div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
<div class="longbox"></div> <!-- Saturate the margin space -->
</body>
</body>
</html>

View File

@ -54,5 +54,5 @@
<div class="box" style="block-size: 36px;"></div>
<div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
<div class="longbox"></div> <!-- Saturate the margin space -->
</body>
</body>
</html>

View File

@ -52,5 +52,5 @@
<div class="box" style="height: 36px;"></div>
<div class="box" style="height: 24px;"></div> <!-- Box at corner -->
<div class="longbox"></div> <!-- Saturate the margin and border space -->
</body>
</body>
</html>

View File

@ -53,5 +53,5 @@
<div class="box" style="height: 36px;"></div>
<div class="box" style="height: 24px;"></div> <!-- Box at corner -->
<div class="longbox"></div> <!-- Saturate the margin and border space -->
</body>
</body>
</html>

View File

@ -0,0 +1,49 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<meta charset="utf-8">
<title>CSS Shape Test: float left, ellipse(40px 60px at left top)</title>
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
<style>
.container {
position: absolute;
width: 200px;
line-height: 0;
}
.shape {
float: left;
/* Omit shape-outside */
clip-path: ellipse(40px 60px at left top);
box-sizing: content-box;
height: 40px;
width: 40px;
padding: 20px;
border: 20px solid lightgreen;
background-color: orange;
}
.box {
position: absolute;
width: 120px;
background-color: blue;
}
.long {
width: 200px;
}
</style>
<body class="container">
<div class="shape"></div>
<div class="shape"></div>
<div class="box" style="height: 36px; top: 0px; left: 40px;"></div>
<div class="box" style="height: 24px; top: 36px; left: 32px;"></div> <!-- Box at corner -->
<div class="long box" style="height: 60px; top: 60px; left: 0px;"></div> <!-- Fill the space between two floats -->
<div class="box" style="height: 36px; top: 120px; left: 40px;"></div>
<div class="box" style="height: 24px; top: 156px; left: 32px;"></div> <!-- Box at corner -->
</body>
</html>

View File

@ -0,0 +1,52 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<meta charset="utf-8">
<title>CSS Shape Test: float left, ellipse(40px 60px at left top)</title>
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
<link rel="match" href="shape-outside-ellipse-001-ref.html">
<meta name="flags" content="">
<meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the basic shape ellipse(40px 60px at left top) value.">
<style>
.container {
width: 200px;
line-height: 0;
}
.shape {
float: left;
shape-outside: ellipse(40px 60px at left top);
clip-path: ellipse(40px 60px at left top);
box-sizing: content-box;
height: 40px;
width: 40px;
padding: 20px;
border: 20px solid lightgreen;
background-color: orange;
}
.box {
display: inline-block;
width: 120px;
background-color: blue;
}
.long {
width: 200px;
}
</style>
<body class="container">
<div class="shape"></div>
<div class="shape"></div>
<div class="box" style="height: 36px;"></div>
<div class="box" style="height: 24px;"></div> <!-- Box at corner -->
<div class="long box" style="height: 60px;"></div> <!-- Fill the space between two floats -->
<div class="box" style="height: 36px;"></div>
<div class="box" style="height: 24px;"></div> <!-- Box at corner -->
</body>
</html>

View File

@ -0,0 +1,52 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<meta charset="utf-8">
<title>CSS Shape Test: float left, ellipse(40px 60px at right bottom)</title>
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
<style>
.container {
position: absolute;
width: 200px;
line-height: 0;
}
.shape {
float: left;
/* Omit shape-outside */
clip-path: ellipse(40px 60px at right bottom);
box-sizing: content-box;
height: 40px;
width: 40px;
padding: 20px;
border: 20px solid lightgreen;
background-color: orange;
}
.box {
position: absolute;
width: 60px;
background-color: blue;
}
.long {
width: 200px;
}
</style>
<body class="container">
<div class="shape"></div>
<div class="shape"></div>
<div class="long box" style="height: 60px; top: 0px; left: 0px;"></div> <!-- Fill the space above the first float -->
<div class="box" style="height: 36px; top: 60px; left: 120px;"></div>
<div class="box" style="height: 12px; top: 96px; left: 120px;"></div>
<div class="box" style="height: 12px; top: 108px; left: 120px;"></div>
<div class="long box" style="height: 60px; top: 120px; left: 0px;"></div> <!-- Fill the space between two floats -->
<div class="box" style="height: 36px; top: 180px; left: 120px;"></div>
<div class="box" style="height: 12px; top: 216px; left: 120px;"></div>
<div class="box" style="height: 12px; top: 228px; left: 120px;"></div>
</body>
</html>

View File

@ -0,0 +1,55 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<meta charset="utf-8">
<title>CSS Shape Test: float left, ellipse(40px 60px at right bottom)</title>
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
<link rel="match" href="shape-outside-ellipse-002-ref.html">
<meta name="flags" content="">
<meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the basic shape ellipse(40px 60px at right bottom) value.">
<style>
.container {
width: 200px;
line-height: 0;
}
.shape {
float: left;
shape-outside: ellipse(40px 60px at right bottom);
clip-path: ellipse(40px 60px at right bottom);
box-sizing: content-box;
height: 40px;
width: 40px;
padding: 20px;
border: 20px solid lightgreen;
background-color: orange;
}
.box {
display: inline-block;
width: 60px;
background-color: blue;
}
.long {
width: 200px;
}
</style>
<body class="container">
<div class="shape"></div>
<div class="shape"></div>
<div class="long box" style="height: 60px;"></div> <!-- Fill the space above the first float -->
<div class="box" style="height: 36px;"></div>
<div class="box" style="height: 12px;"></div>
<div class="box" style="height: 12px;"></div>
<div class="long box" style="height: 60px;"></div> <!-- Fill the space between two floats -->
<div class="box" style="height: 36px;"></div>
<div class="box" style="height: 12px;"></div>
<div class="box" style="height: 12px;"></div>
</body>
</html>

View File

@ -0,0 +1,49 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<meta charset="utf-8">
<title>CSS Shape Test: float right, ellipse(40px 60px at right top)</title>
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
<style>
.container {
position: absolute;
width: 200px;
line-height: 0;
}
.shape {
float: right;
/* Omit shape-outside */
clip-path: ellipse(40px 60px at right top);
box-sizing: content-box;
height: 40px;
width: 40px;
padding: 20px;
border: 20px solid lightgreen;
background-color: orange;
}
.box {
position: absolute;
width: 120px;
background-color: blue;
}
.long {
width: 200px;
}
</style>
<body class="container">
<div class="shape"></div>
<div class="shape"></div>
<div class="box" style="height: 36px; top: 0px; right: 40px;"></div>
<div class="box" style="height: 24px; top: 36px; right: 32px;"></div> <!-- Box at corner -->
<div class="long box" style="height: 60px; top: 60px; right: 0px;"></div> <!-- Fill the space between two floats -->
<div class="box" style="height: 36px; top: 120px; right: 40px;"></div>
<div class="box" style="height: 24px; top: 156px; right: 32px;"></div> <!-- Box at corner -->
</body>
</html>

View File

@ -0,0 +1,53 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<meta charset="utf-8">
<title>CSS Shape Test: float right, ellipse(40px 60px at right top)</title>
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
<link rel="match" href="shape-outside-ellipse-003-ref.html">
<meta name="flags" content="">
<meta name="assert" content="Test the boxes are wrapping around the right float shape defined by the basic shape ellipse(40px 60px at right top)">
<style>
.container {
direction: rtl;
width: 200px;
line-height: 0;
}
.shape {
float: right;
shape-outside: ellipse(40px 60px at right top);
clip-path: ellipse(40px 60px at right top);
box-sizing: content-box;
height: 40px;
width: 40px;
padding: 20px;
border: 20px solid lightgreen;
background-color: orange;
}
.box {
display: inline-block;
width: 120px;
background-color: blue;
}
.long {
width: 200px;
}
</style>
<body class="container">
<div class="shape"></div>
<div class="shape"></div>
<div class="box" style="height: 36px;"></div>
<div class="box" style="height: 24px;"></div> <!-- Box at corner -->
<div class="long box" style="height: 60px;"></div> <!-- Fill the space between two floats -->
<div class="box" style="height: 36px;"></div>
<div class="box" style="height: 24px;"></div> <!-- Box at corner -->
</body>
</html>

View File

@ -0,0 +1,53 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<meta charset="utf-8">
<title>CSS Shape Test: float left, ellipse(40px 60px at left bottom)</title>
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
<style>
.container {
direction: rtl;
position: absolute;
width: 200px;
line-height: 0;
}
.shape {
float: right;
/* Omit shape-outside */
clip-path: ellipse(40px 60px at left bottom);
box-sizing: content-box;
height: 40px;
width: 40px;
padding: 20px;
border: 20px solid lightgreen;
background-color: orange;
}
.box {
position: absolute;
width: 60px;
background-color: blue;
}
.long {
width: 200px;
}
</style>
<body class="container">
<div class="shape"></div>
<div class="shape"></div>
<div class="long box" style="height: 60px; top: 0px; right: 0px;"></div> <!-- Fill the space above the first float -->
<div class="box" style="height: 36px; top: 60px; right: 120px;"></div>
<div class="box" style="height: 12px; top: 96px; right: 120px;"></div>
<div class="box" style="height: 12px; top: 108px; right: 120px;"></div>
<div class="long box" style="height: 60px; top: 120px; right: 0px;"></div> <!-- Fill the space between two floats -->
<div class="box" style="height: 36px; top: 180px; right: 120px;"></div>
<div class="box" style="height: 12px; top: 216px; right: 120px;"></div>
<div class="box" style="height: 12px; top: 228px; right: 120px;"></div>
</body>
</html>

View File

@ -0,0 +1,56 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<meta charset="utf-8">
<title>CSS Shape Test: float right, ellipse(40px 60px at left bottom)</title>
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
<link rel="match" href="shape-outside-ellipse-004-ref.html">
<meta name="flags" content="">
<meta name="assert" content="Test the boxes are wrapping around the right float shape defined by the basic shape ellipse(40px 60px at left bottom) value.">
<style>
.container {
direction: rtl;
width: 200px;
line-height: 0;
}
.shape {
float: right;
shape-outside: ellipse(40px 60px at left bottom);
clip-path: ellipse(40px 60px at left bottom);
box-sizing: content-box;
height: 40px;
width: 40px;
padding: 20px;
border: 20px solid lightgreen;
background-color: orange;
}
.box {
display: inline-block;
width: 60px;
background-color: blue;
}
.long {
width: 200px;
}
</style>
<body class="container">
<div class="shape"></div>
<div class="shape"></div>
<div class="long box" style="height: 60px;"></div> <!-- Fill the space above the first float -->
<div class="box" style="height: 36px;"></div>
<div class="box" style="height: 12px;"></div>
<div class="box" style="height: 12px;"></div>
<div class="long box" style="height: 60px;"></div> <!-- Fill the space between two floats -->
<div class="box" style="height: 36px;"></div>
<div class="box" style="height: 12px;"></div>
<div class="box" style="height: 12px;"></div>
</body>
</html>

View File

@ -0,0 +1,44 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<meta charset="utf-8">
<title>CSS Shape Test: float left, ellipse() reference</title>
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
<style>
.container {
position: absolute;
width: 200px;
line-height: 0;
}
.shape {
float: left;
/* Omit shape-outside */
clip-path: ellipse();
box-sizing: content-box;
height: 40px;
width: 40px;
padding: 20px 10px;
border: solid lightgreen;
border-width: 20px 10px;
background-color: orange;
}
.box {
position: absolute;
width: 80px;
background-color: blue;
}
</style>
<body class="container">
<div class="shape"></div>
<div class="box" style="height: 24px; top: 0px; left: 72px;"></div> <!-- Box at corner -->
<div class="box" style="height: 36px; top: 24px; left: 80px;"></div>
<div class="box" style="height: 36px; top: 60px; left: 80px;"></div>
<div class="box" style="height: 24px; top: 96px; left: 72px;"></div> <!-- Box at corner -->
</body>
</html>

View File

@ -0,0 +1,47 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<meta charset="utf-8">
<title>CSS Shape Test: float left, ellipse()</title>
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
<link rel="match" href="shape-outside-ellipse-005-ref.html">
<meta name="flags" content="">
<meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the basic shape ellipse() value.">
<style>
.container {
width: 200px;
line-height: 0;
}
.shape {
float: left;
shape-outside: ellipse();
clip-path: ellipse();
box-sizing: content-box;
height: 40px;
width: 40px;
padding: 20px 10px;
border: solid lightgreen;
border-width: 20px 10px;
background-color: orange;
}
.box {
display: inline-block;
width: 80px;
background-color: blue;
}
</style>
<body class="container">
<div class="shape"></div>
<div class="box" style="height: 24px;"></div> <!-- Box at corner -->
<div class="box" style="height: 36px;"></div>
<div class="box" style="height: 36px;"></div>
<div class="box" style="height: 24px;"></div> <!-- Box at corner -->
</body>
</html>

View File

@ -0,0 +1,44 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<meta charset="utf-8">
<title>CSS Shape Test: float left, ellipse(closest-side farthest-side at left 40px top 60px) border-box reference</title>
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
<style>
.container {
position: absolute;
width: 200px;
line-height: 0;
}
.shape {
float: left;
/* Omit shape-outside */
clip-path: ellipse(closest-side farthest-side at left 40px top 60px) border-box;
box-sizing: content-box;
height: 40px;
width: 40px;
padding: 20px 10px;
border: solid lightgreen;
border-width: 10px;
background-color: orange;
}
.box {
position: absolute;
width: 80px;
background-color: blue;
}
</style>
<body class="container">
<div class="shape"></div>
<div class="box" style="height: 24px; top: 0px; left: 72px;"></div> <!-- Box at corner -->
<div class="box" style="height: 36px; top: 24px; left: 80px;"></div>
<div class="box" style="height: 36px; top: 60px; left: 80px;"></div>
<div class="box" style="height: 24px; top: 96px; left: 72px;"></div> <!-- Box at corner -->
</body>
</html>

View File

@ -0,0 +1,47 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<meta charset="utf-8">
<title>CSS Shape Test: float left, ellipse(closest-side farthest-side at left 40px top 60px) border-box</title>
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
<link rel="match" href="shape-outside-ellipse-006-ref.html">
<meta name="flags" content="">
<meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the basic shape ellipse(closest-side farthest-side at left 40px top 60px) border-box">
<style>
.container {
width: 200px;
line-height: 0;
}
.shape {
float: left;
shape-outside: ellipse(closest-side farthest-side at left 40px top 60px) border-box;
clip-path: ellipse(closest-side farthest-side at left 40px top 60px) border-box;
box-sizing: content-box;
height: 40px;
width: 40px;
padding: 20px 10px;
border: solid lightgreen;
border-width: 10px;
background-color: orange;
}
.box {
display: inline-block;
width: 80px;
background-color: blue;
}
</style>
<body class="container">
<div class="shape"></div>
<div class="box" style="height: 24px;"></div> <!-- Box at corner -->
<div class="box" style="height: 36px;"></div>
<div class="box" style="height: 36px;"></div>
<div class="box" style="height: 24px;"></div> <!-- Box at corner -->
</body>
</html>

View File

@ -0,0 +1,45 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<meta charset="utf-8">
<title>CSS Shape Test: float right, ellipse() reference</title>
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
<style>
.container {
direction: rtl;
position: absolute;
width: 200px;
line-height: 0;
}
.shape {
float: right;
/* Omit shape-outside */
clip-path: ellipse();
box-sizing: content-box;
height: 40px;
width: 40px;
padding: 20px 10px;
border: solid lightgreen;
border-width: 20px 10px;
background-color: orange;
}
.box {
position: absolute;
width: 80px;
background-color: blue;
}
</style>
<body class="container">
<div class="shape"></div>
<div class="box" style="height: 24px; top: 0px; right: 72px;"></div> <!-- Box at corner -->
<div class="box" style="height: 36px; top: 24px; right: 80px;"></div>
<div class="box" style="height: 36px; top: 60px; right: 80px;"></div>
<div class="box" style="height: 24px; top: 96px; right: 72px;"></div> <!-- Box at corner -->
</body>
</html>

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