mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-28 21:28:55 +00:00
Merge m-c to m-i
This commit is contained in:
commit
39e57631eb
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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()
|
||||
|
@ -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" />
|
||||
|
@ -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
|
||||
}
|
||||
]
|
||||
|
@ -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
|
||||
}
|
||||
]
|
||||
|
@ -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
|
||||
}
|
||||
]
|
||||
|
@ -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
|
||||
}
|
||||
]
|
||||
|
@ -1,2 +0,0 @@
|
||||
wc-reporter.label=Report Site Issue
|
||||
wc-reporter.tooltip=Report a site compatibility issue
|
@ -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
|
@ -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)
|
@ -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'
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -44,7 +44,7 @@ treecol {
|
||||
}
|
||||
|
||||
.learnMore {
|
||||
margin-inline-start: 1.5em;
|
||||
margin-inline-start: 10px;
|
||||
font-weight: normal;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
@ -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% {
|
||||
|
@ -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%;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
24
dom/animation/AnimationRule.h
Normal file
24
dom/animation/AnimationRule.h
Normal 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
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
32
dom/animation/ServoAnimationRule.cpp
Normal file
32
dom/animation/ServoAnimationRule.cpp
Normal 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
|
39
dom/animation/ServoAnimationRule.h
Normal file
39
dom/animation/ServoAnimationRule.h
Normal 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
|
@ -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',
|
||||
]
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
{
|
||||
@ -13809,6 +13824,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)
|
||||
{
|
||||
|
@ -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);
|
||||
@ -1752,9 +1753,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>;
|
||||
@ -1791,6 +1799,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.
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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(),
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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 ;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -503,3 +503,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;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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).
|
||||
//
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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],
|
||||
|
@ -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()
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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
Loading…
x
Reference in New Issue
Block a user