Merge mozilla-central to inbound

This commit is contained in:
Narcis Beleuzu 2019-08-18 00:53:23 +03:00
commit 1ef71e5fc2
178 changed files with 4009 additions and 2002 deletions

View File

@ -45,7 +45,7 @@ exclude =
toolkit/content/tests/chrome/file_about_networking_wsh.py,
toolkit/crashreporter/tools/symbolstore.py,
toolkit/crashreporter/tools/unit-symbolstore.py,
toolkit/library/dependentlibs.py,
toolkit/library/build/dependentlibs.py,
toolkit/locales/generate_update_locale.py,
toolkit/mozapps,
toolkit/moz.configure,

View File

@ -3,5 +3,4 @@ support-files = head.js
[browser_toolbarButtonKeyPress.js]
[browser_toolbarKeyNav.js]
skip-if = fission && debug # Crashes: @ mozilla::dom::ServiceWorkerManagerService::PropagateRegistration(unsigned long, mozilla::dom::ServiceWorkerRegistrationData&)
support-files = !/browser/base/content/test/permissions/permissions.html

View File

@ -6,21 +6,16 @@ support-files=
[browser_canvas_fingerprinting_resistance.js]
skip-if = debug || os == "linux" && asan # Bug 1522069
[browser_permissions.js]
skip-if = fission && debug # Crashes: @ mozilla::dom::ServiceWorkerManagerService::PropagateUnregister(unsigned long, mozilla::ipc::PrincipalInfo const&, nsTSubstring<char16_t> const&)
[browser_permissions_event_telemetry.js]
skip-if = fission && debug
[browser_permissions_postPrompt.js]
skip-if = fission && debug # Crashes: @ mozilla::dom::ServiceWorkerManagerService::PropagateUnregister(unsigned long, mozilla::ipc::PrincipalInfo const&, nsTSubstring<char16_t> const&)
support-files=
dummy.js
[browser_permissions_handling_user_input.js]
skip-if = fission && debug # Crashes: @ mozilla::dom::ServiceWorkerManagerService::PropagateRegistration(unsigned long, mozilla::dom::ServiceWorkerRegistrationData&)
support-files=
dummy.js
[browser_reservedkey.js]
skip-if = fission && debug # Crashes: @ mozilla::dom::ServiceWorkerManagerService::PropagateUnregister(unsigned long, mozilla::ipc::PrincipalInfo const&, nsTSubstring<char16_t> const&)
[browser_temporary_permissions.js]
fail-if = fission
fail-if = fission # SecurityError: Permission denied to access property "document" on cross-origin object
support-files =
temporary_permissions_subframe.html
../webrtc/get_user_media.html
@ -32,6 +27,5 @@ support-files =
../general/audio.ogg
skip-if = verify && os == 'linux' && debug # Bug 1483648
[browser_temporary_permissions_expiry.js]
skip-if = fission && debug # Crashes: @ mozilla::dom::ServiceWorkerManagerService::PropagateUnregister(unsigned long, mozilla::ipc::PrincipalInfo const&, nsTSubstring<char16_t> const&)
[browser_temporary_permissions_navigation.js]
[browser_temporary_permissions_tabs.js]

View File

@ -1034,6 +1034,19 @@ nsDefaultCommandLineHandler.prototype = {
if (win) {
win.close();
}
// If this is a silent run where we do not open any window, we must
// notify shutdown so that the quit-application-granted notification
// will happen. This is required in the AddonManager to properly
// handle shutdown blockers for Telemetry and XPIDatabase.
// Some command handlers open a window asynchronously, so lets give
// that time and then verify that a window was not opened before
// quiting.
Services.tm.idleDispatchToMainThread(() => {
win = Services.wm.getMostRecentWindow(null);
if (!win) {
Services.startup.quit(Services.startup.eForceQuit);
}
}, 1);
}
},

View File

@ -69,7 +69,8 @@ add_task(async function test() {
() =>
(notification = gBrowser
.getNotificationBox()
.getNotificationWithValue("master-password-login-required"))
.getNotificationWithValue("master-password-login-required")),
"waiting for master-password-login-required notification"
);
ok(

View File

@ -78,6 +78,10 @@ Preferences.addAll([
{ id: "privacy.trackingprotection.fingerprinting.enabled", type: "bool" },
{ id: "privacy.trackingprotection.cryptomining.enabled", type: "bool" },
// Social tracking
{ id: "privacy.trackingprotection.socialtracking.enabled", type: "bool" },
{ id: "privacy.socialtracking.block_cookies.enabled", type: "bool" },
// Tracker list
{ id: "urlclassifier.trackingTable", type: "string" },
@ -1057,6 +1061,12 @@ var gPrivacyPane = {
trackingProtectionWritePrefs() {
let enabledPref = Preferences.get("privacy.trackingprotection.enabled");
let pbmPref = Preferences.get("privacy.trackingprotection.pbmode.enabled");
let stpPref = Preferences.get(
"privacy.trackingprotection.socialtracking.enabled"
);
let stpCookiePref = Preferences.get(
"privacy.socialtracking.block_cookies.enabled"
);
let tpMenu = document.getElementById("trackingProtectionMenu");
let tpCheckbox = document.getElementById(
"contentBlockingTrackingProtectionCheckbox"
@ -1077,14 +1087,23 @@ var gPrivacyPane = {
case "always":
enabledPref.value = true;
pbmPref.value = true;
if (stpCookiePref.value) {
stpPref.value = true;
}
break;
case "private":
enabledPref.value = false;
pbmPref.value = true;
if (stpCookiePref.value) {
stpPref.value = false;
}
break;
case "never":
enabledPref.value = false;
pbmPref.value = false;
if (stpCookiePref.value) {
stpPref.value = false;
}
break;
}
},

View File

@ -23,8 +23,6 @@ from distutils.dir_util import copy_tree
from shutil import which
URL_REPO = "https://github.com/llvm/llvm-project"
def symlink(source, link_name):
os_symlink = getattr(os, "symlink", None)
@ -182,16 +180,16 @@ def install_libgcc(gcc_dir, clang_dir, is_final_stage):
"x86_64-unknown-linux-gnu",
os.path.basename(libgcc_dir))
mkdir_p(clang_lib_dir)
copy_tree(libgcc_dir, clang_lib_dir)
copy_tree(libgcc_dir, clang_lib_dir, preserve_symlinks=True)
libgcc_dir = os.path.join(gcc_dir, "lib64")
clang_lib_dir = os.path.join(clang_dir, "lib")
copy_tree(libgcc_dir, clang_lib_dir)
copy_tree(libgcc_dir, clang_lib_dir, preserve_symlinks=True)
libgcc_dir = os.path.join(gcc_dir, "lib32")
clang_lib_dir = os.path.join(clang_dir, "lib32")
copy_tree(libgcc_dir, clang_lib_dir)
copy_tree(libgcc_dir, clang_lib_dir, preserve_symlinks=True)
include_dir = os.path.join(gcc_dir, "include")
clang_include_dir = os.path.join(clang_dir, "include")
copy_tree(include_dir, clang_include_dir)
copy_tree(include_dir, clang_include_dir, preserve_symlinks=True)
def install_import_library(build_dir, clang_dir):

View File

@ -27,6 +27,7 @@ protected:
if (Name == "pair" || Name == "atomic" ||
// libstdc++ specific names
Name == "__atomic_base" || Name == "atomic_bool" ||
Name == "__cxx_atomic_impl" || Name == "__cxx_atomic_base_impl" ||
Name == "__pair_base" ||
// MSVCRT specific names
Name == "_Atomic_impl" || Name == "_Atomic_base" ||

View File

@ -25,7 +25,7 @@ def GeckoBinary(linkage='dependent', mozglue=None):
if linkage == 'dependent':
USE_LIBS += [
'nspr',
'xul',
'xul-real',
]
elif linkage == 'standalone':
DEFINES['XPCOM_GLUE'] = True

View File

@ -19,7 +19,7 @@ ifdef SHARED_LIBRARY
SHARED_LIBRARY_FILES = $(SHARED_LIBRARY)
SHARED_LIBRARY_DEST ?= $(FINAL_TARGET)
ifndef SHARED_LIBRARY_TARGET
SHARED_LIBRARY_TARGET = target-shared
SHARED_LIBRARY_TARGET = target
endif
INSTALL_TARGETS += SHARED_LIBRARY
endif # SHARED_LIBRARY

View File

@ -73,12 +73,7 @@ CURRENT_DIRS := $($(CURRENT_TIER)_dirs)
$(compile_targets) $(syms_targets):
$(if $(filter $(RECURSE_BASE_DIR)%,$@),$(call RECURSE,$(@F),$(@D)))
# Equivalent to a mix of:
# $(syms_targets): %/syms: %/target
# and
# $(syms_targets): %/syms: %/target-shared
# for the right syms targets.
$(foreach syms_target,$(syms_targets),$(eval $(syms_target): $(filter $(dir $(syms_target))target $(dir $(syms_target))target-shared,$(compile_targets))))
$(syms_targets): %/syms: %/target
# Only hook symbols targets into the main compile graph in automation.
ifdef MOZ_AUTOMATION
@ -187,14 +182,14 @@ xpcom/xpidl/export: xpcom/idl-parser/xpidl/export
dom/bindings/export: layout/style/export
ifdef ENABLE_CLANG_PLUGIN
$(filter-out config/host build/unix/stdc++compat/% build/clang-plugin/%,$(compile_targets)): build/clang-plugin/host build/clang-plugin/tests/target
build/clang-plugin/tests/target: build/clang-plugin/host
$(filter-out config/host build/unix/stdc++compat/% build/clang-plugin/%,$(compile_targets)): build/clang-plugin/host build/clang-plugin/tests/target-objects
build/clang-plugin/tests/target-objects: build/clang-plugin/host
endif
# Interdependencies that moz.build world don't know about yet for compilation.
# Note some others are hardcoded or "guessed" in recursivemake.py and emitter.py
ifeq ($(MOZ_WIDGET_TOOLKIT),gtk3)
toolkit/library/target-shared: widget/gtk/mozgtk/gtk3/target-shared
toolkit/library/target: widget/gtk/mozgtk/gtk3/target
endif
endif
# Most things are built during compile (target/host), but some things happen during export

View File

@ -412,8 +412,7 @@ compile:: host target
host:: $(HOST_OBJS) $(HOST_PROGRAM) $(HOST_SIMPLE_PROGRAMS) $(HOST_RUST_PROGRAMS) $(HOST_RUST_LIBRARY_FILE) $(HOST_SHARED_LIBRARY)
target:: $(filter-out $(MOZBUILD_NON_DEFAULT_TARGETS),$(LIBRARY) $(PROGRAM) $(SIMPLE_PROGRAMS) $(RUST_LIBRARY_FILE) $(RUST_PROGRAMS))
target-shared:: $(filter-out $(MOZBUILD_NON_DEFAULT_TARGETS),$(SHARED_LIBRARY))
target:: $(filter-out $(MOZBUILD_NON_DEFAULT_TARGETS),$(LIBRARY) $(SHARED_LIBRARY) $(PROGRAM) $(SIMPLE_PROGRAMS) $(RUST_LIBRARY_FILE) $(RUST_PROGRAMS))
ifndef LIBRARY
ifdef OBJS
@ -421,6 +420,9 @@ target:: $(OBJS)
endif
endif
target-objects: $(OBJS) $(PROGOBJS)
host-objects: $(HOST_OBJS) $(HOST_PROGOBJS)
syms::
include $(MOZILLA_DIR)/config/makefiles/target_binaries.mk
@ -511,11 +513,11 @@ endef
# PROGRAM = Foo
# creates OBJS, links with LIBS to create Foo
#
$(PROGRAM): $(PROGOBJS) $(STATIC_LIBS) $(RUST_STATIC_LIB) $(EXTRA_DEPS) $(RESFILE) $(GLOBAL_DEPS) $(call mkdir_deps,$(FINAL_TARGET))
$(PROGRAM): $(PROGOBJS) $(STATIC_LIBS) $(EXTRA_DEPS) $(RESFILE) $(GLOBAL_DEPS) $(call mkdir_deps,$(FINAL_TARGET))
$(REPORT_BUILD)
@$(RM) $@.manifest
ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
$(LINKER) -NOLOGO -OUT:$@ -PDB:$(LINK_PDBFILE) -IMPLIB:$(basename $(@F)).lib $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $($(notdir $@)_$(OBJS_VAR_SUFFIX)) $(RESFILE) $(STATIC_LIBS) $(RUST_STATIC_LIB) $(SHARED_LIBS) $(OS_LIBS)
$(LINKER) -NOLOGO -OUT:$@ -PDB:$(LINK_PDBFILE) -IMPLIB:$(basename $(@F)).lib $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $($(notdir $@)_$(OBJS_VAR_SUFFIX)) $(RESFILE) $(STATIC_LIBS) $(SHARED_LIBS) $(OS_LIBS)
ifdef MSMANIFEST_TOOL
@if test -f $@.manifest; then \
if test -f '$(srcdir)/$(notdir $@).manifest'; then \
@ -536,7 +538,7 @@ ifdef MOZ_PROFILE_GENERATE
touch -t `date +%Y%m%d%H%M.%S -d 'now+5seconds'` pgo.relink
endif
else # !WINNT || GNU_CC
$(call EXPAND_CC_OR_CXX,$@) -o $@ $(COMPUTED_CXX_LDFLAGS) $(PGO_CFLAGS) $($(notdir $@)_$(OBJS_VAR_SUFFIX)) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(STATIC_LIBS) $(RUST_STATIC_LIB) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(OS_LIBS)
$(call EXPAND_CC_OR_CXX,$@) -o $@ $(COMPUTED_CXX_LDFLAGS) $(PGO_CFLAGS) $($(notdir $@)_$(OBJS_VAR_SUFFIX)) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(OS_LIBS)
$(call py_action,check_binary,--target $@)
endif # WINNT && !GNU_CC
@ -653,12 +655,12 @@ endif
# symlinks back to the originals. The symlinks are a no-op for stabs debugging,
# so no need to conditionalize on OS version or debugging format.
$(SHARED_LIBRARY): $(OBJS) $(RESFILE) $(RUST_STATIC_LIB) $(STATIC_LIBS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
$(SHARED_LIBRARY): $(OBJS) $(RESFILE) $(STATIC_LIBS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
$(REPORT_BUILD)
ifndef INCREMENTAL_LINKER
$(RM) $@
endif
$(MKSHLIB) $($@_$(OBJS_VAR_SUFFIX)) $(RESFILE) $(LDFLAGS) $(STATIC_LIBS) $(RUST_STATIC_LIB) $(SHARED_LIBS) $(EXTRA_DSO_LDOPTS) $(MOZ_GLUE_LDFLAGS) $(OS_LIBS)
$(MKSHLIB) $($@_$(OBJS_VAR_SUFFIX)) $(RESFILE) $(LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_DSO_LDOPTS) $(MOZ_GLUE_LDFLAGS) $(OS_LIBS)
$(call py_action,check_binary,--target $@)
ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))

View File

@ -23,6 +23,16 @@ add_task(async function() {
await stepInToLine(threadFront, 30);
await stepOverToLine(threadFront, 31);
await stepOverToLine(threadFront, 32);
// Check that the scopes pane shows the value of the local variable.
await waitForPaused(dbg);
for (let i = 1; ; i++) {
if (getScopeLabel(dbg, i) == "c") {
is("NaN", getScopeValue(dbg, i));
break;
}
}
await stepOverToLine(threadFront, 33);
await reverseStepOverToLine(threadFront, 32);
await stepOutToLine(threadFront, 27);

View File

@ -1097,13 +1097,12 @@ function waitUntilPauseFinishes() {
return;
}
while (true) {
while (gPauseMode != PauseModes.PAUSED) {
gActiveChild.waitUntilPaused();
if (pointEquals(gActiveChild.pausePoint(), gPausePoint)) {
return;
}
pokeChild(gActiveChild);
}
gActiveChild.waitUntilPaused();
}
// Synchronously send a child to the specific point and pause.

View File

@ -408,7 +408,7 @@ ReplayDebugger.prototype = {
if (!this._objects[data.id]) {
this._addObject(data);
}
this._getObject(data.id)._names = names;
this._getObject(data.id)._setNames(names);
}
for (const frame of pauseData.frames) {
@ -1297,6 +1297,13 @@ ReplayDebuggerEnvironment.prototype = {
return this._data.optimizedOut;
},
_setNames(names) {
this._names = {};
names.forEach(({ name, value }) => {
this._names[name] = this._dbg._convertValue(value);
});
},
_ensureNames() {
if (!this._names) {
const names = this._dbg._sendRequestAllowDiverge(
@ -1306,10 +1313,7 @@ ReplayDebuggerEnvironment.prototype = {
},
[]
);
this._names = {};
names.forEach(({ name, value }) => {
this._names[name] = this._dbg._convertValue(value);
});
this._setNames(names);
}
},

View File

@ -1471,6 +1471,8 @@ function getPauseData() {
const names = getEnvironmentNames(env);
rv.environments[id] = { data, names };
names.forEach(({ value }) => addValue(value, true));
addObject(data.callee);
addEnvironment(data.parent);
}

View File

@ -9390,7 +9390,7 @@ static Maybe<LayoutDeviceToScreenScale> ParseScaleString(
}
nsresult scaleErrorCode;
float scale = aScaleString.ToFloat(&scaleErrorCode);
float scale = aScaleString.ToFloatAllowTrailingChars(&scaleErrorCode);
if (NS_FAILED(scaleErrorCode)) {
return Some(LayoutDeviceToScreenScale(kViewportMinScale));
}

View File

@ -39,9 +39,10 @@ void nsWrapperCache::SetWrapperJSObject(JSObject* aWrapper) {
CycleCollectedJSRuntime::Get()->NurseryWrapperAdded(this);
}
if (mozilla::recordreplay::IsReplaying()) {
mozilla::recordreplay::SetWeakPointerJSRoot(this, aWrapper);
}
// Never collect the wrapper object while recording or replaying, to avoid
// non-deterministic behaviors if the cache is emptied and then refilled at
// a different point when replaying.
recordreplay::HoldJSObject(aWrapper);
}
void nsWrapperCache::ReleaseWrapper(void* aScriptObjectHolder) {
@ -98,12 +99,6 @@ static void DebugWrapperTraceCallback(JS::GCCellPtr aPtr, const char* aName,
void nsWrapperCache::CheckCCWrapperTraversal(void* aScriptObjectHolder,
nsScriptObjectTracer* aTracer) {
// Skip checking if we are recording or replaying, as calling
// GetWrapperPreserveColor() can cause the cache's wrapper to be cleared.
if (recordreplay::IsRecordingOrReplaying()) {
return;
}
JSObject* wrapper = GetWrapperPreserveColor();
if (!wrapper) {
return;

View File

@ -82,10 +82,6 @@ static_assert(sizeof(void*) == 4, "Only support 32-bit and 64-bit");
* A number of the methods are implemented in nsWrapperCacheInlines.h because we
* have to include some JS headers that don't play nicely with the rest of the
* codebase. Include nsWrapperCacheInlines.h if you need to call those methods.
*
* When recording or replaying an execution, wrapper caches are instrumented so
* that they behave consistently even if the GC executes at different points
* and collects different objects.
*/
class nsWrapperCache {
@ -102,10 +98,6 @@ class nsWrapperCache {
{
}
~nsWrapperCache() {
// Clear any JS root associated with this cache while replaying.
if (mozilla::recordreplay::IsReplaying()) {
mozilla::recordreplay::SetWeakPointerJSRoot(this, nullptr);
}
// Preserved wrappers should never end up getting cleared, but this can
// happen during shutdown when a leaked wrapper object is finalized, causing
// its wrapper to be cleared.
@ -145,23 +137,6 @@ class nsWrapperCache {
* escape.
*/
JSObject* GetWrapperMaybeDead() const {
// Keep track of accesses on the cache when recording or replaying an
// execution. Accesses during a GC (when thread events are disallowed)
// fetch the underlying object without making sure the returned value
// is consistent between recording and replay.
if (mozilla::recordreplay::IsRecordingOrReplaying() &&
!mozilla::recordreplay::AreThreadEventsDisallowed() &&
!mozilla::recordreplay::HasDivergedFromRecording()) {
bool success = mozilla::recordreplay::RecordReplayValue(!!mWrapper);
if (mozilla::recordreplay::IsReplaying()) {
if (success) {
MOZ_RELEASE_ASSERT(mWrapper);
} else {
const_cast<nsWrapperCache*>(this)->ClearWrapper();
}
}
}
return mWrapper;
}

View File

@ -763,6 +763,8 @@ skip-if = !e10s # Track Bug 1281415
[test_meta_viewport_remove_node_from_multiple.html]
[test_meta_viewport_replace_content.html]
[test_meta_viewport_tiny_display_size.html]
[test_meta_viewport_initial_scale_with_trailing_characters.html]
[test_meta_viewport_width_with_trailing_characters.html]
[test_mozbrowser_apis_blocked.html]
[test_mozMatchesSelector.html]
[test_mutationobserver_anonymous.html]

View File

@ -0,0 +1,26 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>initial-scale with trailing characters in meta viewport</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<meta name="viewport" content="initial-scale=1.0/">
<script src="viewport_helpers.js"></script>
</head>
<body>
<p>initial-scale=1.0/</p>
<script type="application/javascript">
"use strict";
add_task(async function initial_scale_with_trailing_characters() {
await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
let info = getViewportInfo(800, 480);
is(info.width, 800, "width should be scaled by 1 / initial-scale");
is(info.height, 480, "height should be scaled by 1 / initial-scale");
is(info.defaultZoom, 1, "initial-scale should be 1");
});
</script>
</body>
</html>

View File

@ -0,0 +1,26 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>width with trailing characters in meta viewport</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<meta name="viewport" content="width=400/">
<script src="viewport_helpers.js"></script>
</head>
<body>
<p>width=400/</p>
<script type="application/javascript">
"use strict";
add_task(async function width_with_trailing_characters() {
await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
let info = getViewportInfo(800, 480);
is(info.width, 400, "width should be 400");
is(info.height, 240, "height should be 240 which is the result of the " +
"display height * viewport width / display width");
});
</script>
</body>
</html>

View File

@ -1368,18 +1368,9 @@ inline mozilla::dom::ReflectionScope GetReflectionScope(
template <class T>
inline void ClearWrapper(T* p, nsWrapperCache* cache, JSObject* obj) {
// Skip clearing the wrapper when replaying. This method is called during
// finalization of |obj|, and when replaying a strong reference is kept on
// the contents of the cache: since |obj| is being finalized, the cache
// cannot point to |obj|, and clearing here won't do anything.
// Additionally, the reference held on the cache may have already been
// released, if we are finalizing later than we did while recording, and the
// cache may have already been deleted.
if (!recordreplay::IsReplaying()) {
MOZ_ASSERT(cache->GetWrapperMaybeDead() == obj ||
(js::RuntimeIsBeingDestroyed() && !cache->GetWrapperMaybeDead()));
cache->ClearWrapper(obj);
}
MOZ_ASSERT(cache->GetWrapperMaybeDead() == obj ||
(js::RuntimeIsBeingDestroyed() && !cache->GetWrapperMaybeDead()));
cache->ClearWrapper(obj);
}
template <class T>
@ -1387,13 +1378,9 @@ inline void ClearWrapper(T* p, void*, JSObject* obj) {
// QueryInterface to nsWrapperCache can't GC, we hope.
JS::AutoSuppressGCAnalysis nogc;
// Skip clearing the wrapper when replaying, for the same reason as in the
// overload above: |p| may have been deleted and we cannot QI it.
if (!recordreplay::IsReplaying()) {
nsWrapperCache* cache;
CallQueryInterface(p, &cache);
ClearWrapper(p, cache, obj);
}
nsWrapperCache* cache;
CallQueryInterface(p, &cache);
ClearWrapper(p, cache, obj);
}
template <class T>
@ -2562,11 +2549,6 @@ bool ToSupportsIsOnPrimaryInheritanceChain(T* aObject, nsWrapperCache* aCache) {
// object types.
inline size_t BindingJSObjectMallocBytes(void* aNativePtr) { return 0; }
// Register a thing which DeferredFinalize might be called on during GC
// finalization. See DeferredFinalize.h
template <class T>
static void RecordReplayRegisterDeferredFinalize(T* aObject);
// The BindingJSObjectCreator class is supposed to be used by a caller that
// wants to create and initialise a binding JSObject. After initialisation has
// been successfully completed it should call ForgetObject().
@ -2632,7 +2614,10 @@ class MOZ_STACK_CLASS BindingJSObjectCreator {
void InitializationSucceeded() {
T* pointer;
mNative.forget(&pointer);
RecordReplayRegisterDeferredFinalize<T>(pointer);
// Never collect binding objects while recording or replaying, to avoid
// non-deterministically releasing references during finalization.
recordreplay::HoldJSObject(mReflector);
mReflector = nullptr;
}
@ -2727,12 +2712,6 @@ struct DeferredFinalizer {
DeferredFinalize(Impl::AppendDeferredFinalizePointer,
Impl::DeferredFinalize, aObject);
}
static void RecordReplayRegisterDeferredFinalize(T* aObject) {
typedef DeferredFinalizerImpl<T> Impl;
RecordReplayRegisterDeferredFinalizeThing(
Impl::AppendDeferredFinalizePointer, Impl::DeferredFinalize, aObject);
}
};
template <class T>
@ -2740,10 +2719,6 @@ struct DeferredFinalizer<T, true> {
static void AddForDeferredFinalization(T* aObject) {
DeferredFinalize(reinterpret_cast<nsISupports*>(aObject));
}
static void RecordReplayRegisterDeferredFinalize(T* aObject) {
RecordReplayRegisterDeferredFinalizeThing(nullptr, nullptr, aObject);
}
};
template <class T>
@ -2751,11 +2726,6 @@ static void AddForDeferredFinalization(T* aObject) {
DeferredFinalizer<T>::AddForDeferredFinalization(aObject);
}
template <class T>
static void RecordReplayRegisterDeferredFinalize(T* aObject) {
DeferredFinalizer<T>::RecordReplayRegisterDeferredFinalize(aObject);
}
// This returns T's CC participant if it participates in CC and does not inherit
// from nsISupports. Otherwise, it returns null. QI should be used to get the
// participant if T inherits from nsISupports.
@ -2865,7 +2835,6 @@ bool CreateGlobal(JSContext* aCx, T* aNative, nsWrapperCache* aCache,
NS_ADDREF(aNative);
aCache->SetWrapper(aGlobal);
RecordReplayRegisterDeferredFinalize<T>(aNative);
dom::AllocateProtoAndIfaceCache(
aGlobal, CreateGlobalOptions<T>::ProtoAndIfaceCacheKind);

View File

@ -29,7 +29,7 @@ interface nsICommandManager : nsISupports
{
/*
* Register an observer on the specified command. The observer's Observe
* method will get called when the state (enabled/disbaled, or toggled etc)
* method will get called when the state (enabled/disabled, or toggled etc)
* of the command changes.
*
* You can register the same observer on multiple commmands by calling this

View File

@ -8,7 +8,7 @@
<script type="application/javascript">
createHTML({
bug: "1167443",
title: "Basic audio & video call with disabled bundle and disbaled RTCP-Mux"
title: "Basic audio & video call with disabled bundle and disabled RTCP-Mux"
});
var test;

View File

@ -48,6 +48,7 @@
#include "mozilla/net/CookieSettings.h"
#include "mozilla/net/NeckoChannelParams.h"
#include "mozilla/Services.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/Unused.h"
#include "nsIReferrerInfo.h"
@ -98,8 +99,13 @@ ServiceWorkerPrivate::ServiceWorkerPrivate(ServiceWorkerInfo* aInfo)
if (ServiceWorkerParentInterceptEnabled()) {
RefPtr<ServiceWorkerPrivateImpl> inner = new ServiceWorkerPrivateImpl(this);
nsresult rv = inner->Initialize();
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
// Assert in all debug builds as well as non-debug Nightly and Dev Edition.
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(inner->Initialize()));
#else
MOZ_ALWAYS_SUCCEEDS(inner->Initialize());
#endif
mInner = inner.forget();
}

View File

@ -20,28 +20,21 @@ support-files =
[browser_antitracking.js]
[browser_antitracking_subiframes.js]
skip-if = fission
[browser_devtools_serviceworker_interception.js]
skip-if =
serviceworker_e10s ||
fission && debug # Causes shutdown crashes under Fission.
fission && debug # Causes shutdown crashes under Fission. Assertion failure: parentFound
[browser_force_refresh.js]
skip-if = fission
[browser_download.js]
skip-if = fission && debug # Crashes: @ mozilla::dom::ServiceWorkerManagerService::PropagateUnregister(unsigned long, mozilla::ipc::PrincipalInfo const&, nsTSubstring<char16_t> const&)
[browser_download_canceled.js]
skip-if = verify || (fission && debug) # Crashes: @ mozilla::dom::ServiceWorkerManagerService::PropagateUnregister(unsigned long, mozilla::ipc::PrincipalInfo const&, nsTSubstring<char16_t> const&)
skip-if = verify
[browser_navigation_process_swap.js]
skip-if = fission || !e10s || verify # Bug 1548643
[browser_storage_permission.js]
skip-if =
(verify && debug && (os == 'win' || os == 'mac')) ||
fission && debug # Crashes: @ mozilla::dom::ServiceWorkerManagerService::PropagateUnregister(unsigned long, mozilla::ipc::PrincipalInfo const&, nsTSubstring<char16_t> const&)
skip-if = verify && debug && (os == 'win' || os == 'mac'))
[browser_storage_recovery.js]
skip-if = fission || serviceworker_e10s # Fails intermittently under Fission
[browser_unregister_with_containers.js]
skip-if = fission && debug # Crashes: @ mozilla::dom::ServiceWorkerManagerService::PropagateUnregister(unsigned long, mozilla::ipc::PrincipalInfo const&, nsTSubstring<char16_t> const&)
[browser_userContextId_openWindow.js]
skip-if =
!e10s || serviceworker_e10s ||
(fission && debug) # Crashes: @ mozilla::dom::ServiceWorkerManagerService::PropagateUnregister(unsigned long, mozilla::ipc::PrincipalInfo const&, nsTSubstring<char16_t> const&)
skip-if = !e10s || serviceworker_e10s

View File

@ -863,9 +863,12 @@ nsresult nsXBLBinding::DoInitJSClass(JSContext* cx, JS::Handle<JSObject*> obj,
nsXBLDocumentInfo* docInfo = aProtoBinding->XBLDocumentInfo();
::JS_SetPrivate(proto, docInfo);
NS_ADDREF(docInfo);
RecordReplayRegisterDeferredFinalize(docInfo);
JS_SetReservedSlot(proto, 0, JS::PrivateValue(aProtoBinding));
// Don't collect the proto while recording/replaying, to avoid
// non-deterministically releasing the docInfo reference.
recordreplay::HoldJSObject(proto);
// Next, enter the realm of the property holder, wrap the proto, and
// stick it on.
JSAutoRealm ar3(cx, holder);

View File

@ -373,8 +373,8 @@ class MOZ_STACK_CLASS LayerMetricsWrapper final {
EventRegionsOverride GetEventRegionsOverride() const {
MOZ_ASSERT(IsValid());
if (mLayer->AsRefLayer()) {
return mLayer->AsRefLayer()->GetEventRegionsOverride();
if (AsRefLayer()) {
return AsRefLayer()->GetEventRegionsOverride();
}
return EventRegionsOverride::NoOverride;
}

View File

@ -326,7 +326,11 @@ class MOZ_STACK_CLASS WebRenderScrollDataWrapper final {
EventRegionsOverride GetEventRegionsOverride() const {
MOZ_ASSERT(IsValid());
return mLayer->GetEventRegionsOverride();
// Only ref layers can have an event regions override.
if (GetReferentId()) {
return mLayer->GetEventRegionsOverride();
}
return EventRegionsOverride::NoOverride;
}
const ScrollbarData& GetScrollbarData() const {

View File

@ -27,6 +27,15 @@ flat varying int vFuncs[4];
#define FILTER_OFFSET 7
#define FILTER_COMPONENT_TRANSFER 8
#define FILTER_IDENTITY 9
#define FILTER_COMPOSITE 10
#define COMPOSITE_OVER 0
#define COMPOSITE_IN 1
#define COMPOSITE_OUT 2
#define COMPOSITE_ATOP 3
#define COMPOSITE_XOR 4
#define COMPOSITE_LIGHTER 5
#define COMPOSITE_ARITHMETIC 6
#ifdef WR_VERTEX_SHADER
@ -141,6 +150,12 @@ void main(void) {
case FILTER_COMPONENT_TRANSFER:
vData = ivec4(aFilterExtraDataAddress, 0, 0);
break;
case FILTER_COMPOSITE:
vData = ivec4(aFilterGenericInt, 0, 0, 0);
if (aFilterGenericInt == COMPOSITE_ARITHMETIC) {
vFilterData0 = fetch_from_gpu_cache_1_direct(aFilterExtraDataAddress);
}
break;
default:
break;
}
@ -452,6 +467,46 @@ vec4 ComponentTransfer(vec4 colora) {
return colora;
}
// Composite Filter
vec4 composite(vec4 Cs, vec4 Cb, int mode) {
vec4 Cr = vec4(0.0, 1.0, 0.0, 1.0);
switch (mode) {
case COMPOSITE_OVER:
Cr.rgb = Cs.a * Cs.rgb + Cb.a * Cb.rgb * (1.0 - Cs.a);
Cr.a = Cs.a + Cb.a * (1.0 - Cs.a);
break;
case COMPOSITE_IN:
Cr.rgb = Cs.a * Cs.rgb * Cb.a;
Cr.a = Cs.a * Cb.a;
break;
case COMPOSITE_OUT:
Cr.rgb = Cs.a * Cs.rgb * (1.0 - Cb.a);
Cr.a = Cs.a * (1.0 - Cb.a);
break;
case COMPOSITE_ATOP:
Cr.rgb = Cs.a * Cs.rgb * Cb.a + Cb.a * Cb.rgb * (1.0 - Cs.a);
Cr.a = Cs.a * Cb.a + Cb.a * (1.0 - Cs.a);
break;
case COMPOSITE_XOR:
Cr.rgb = Cs.a * Cs.rgb * (1.0 - Cb.a) + Cb.a * Cb.rgb * (1.0 - Cs.a);
Cr.a = Cs.a * (1.0 - Cb.a) + Cb.a * (1.0 - Cs.a);
break;
case COMPOSITE_LIGHTER:
Cr.rgb = Cs.a * Cs.rgb + Cb.a * Cb.rgb;
Cr.a = Cs.a + Cb.a;
Cr = clamp(Cr, vec4(0.0), vec4(1.0));
break;
case COMPOSITE_ARITHMETIC:
Cr = vec4(vFilterData0.x) * Cs * Cb + vec4(vFilterData0.y) * Cs + vec4(vFilterData0.z) * Cb + vec4(vFilterData0.w);
Cr = clamp(Cr, vec4(0.0), vec4(1.0));
break;
default:
break;
}
return Cr;
}
vec4 sampleInUvRect(sampler2DArray sampler, vec3 uv, vec4 uvRect) {
vec2 clamped = clamp(uv.xy, uvRect.xy, uvRect.zw);
return texture(sampler, vec3(clamped, uv.z), 0.0);
@ -521,6 +576,9 @@ void main(void) {
case FILTER_IDENTITY:
result = Ca;
break;
case FILTER_COMPOSITE:
result = composite(Ca, Cb, vData.x);
needsPremul = false;
default:
break;
}

View File

@ -1956,6 +1956,10 @@ impl PictureCompositeMode {
primitive.input1.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect)
.union(&primitive.input2.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect))
}
FilterPrimitiveKind::Composite(ref primitive) => {
primitive.input1.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect)
.union(&primitive.input2.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect))
}
FilterPrimitiveKind::Identity(ref primitive) =>
primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect),
FilterPrimitiveKind::Opacity(ref primitive) =>

View File

@ -2037,12 +2037,13 @@ impl PrimitiveStore {
}
// Inflate the local rect for this primitive by the inflation factor of
// the picture context. This ensures that even if the primitive itself
// is not visible, any effects from the blur radius will be correctly
// taken into account.
// the picture context and include the shadow offset. This ensures that
// even if the primitive itself is not visible, any effects from the
// blur radius or shadow will be correctly taken into account.
let inflation_factor = surface.inflation_factor;
let local_rect = prim_local_rect
.inflate(inflation_factor, inflation_factor)
.union(&prim_shadow_rect)
.intersection(&prim_instance.local_clip_rect);
let local_rect = match local_rect {
Some(local_rect) => local_rect,

View File

@ -4,7 +4,7 @@
use api::{
ColorU, MixBlendMode, FilterPrimitiveInput, FilterPrimitiveKind, ColorSpace,
PropertyBinding, PropertyBindingId,
PropertyBinding, PropertyBindingId, CompositeOperator,
};
use api::units::{Au, LayoutSize, LayoutVector2D};
use crate::display_list_flattener::IsVisible;
@ -19,6 +19,41 @@ use crate::prim_store::{
InternablePrimitive,
};
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, Clone, MallocSizeOf, PartialEq, Hash, Eq)]
pub enum CompositeOperatorKey {
Over,
In,
Out,
Atop,
Xor,
Lighter,
Arithmetic([Au; 4]),
}
impl From<CompositeOperator> for CompositeOperatorKey {
fn from(operator: CompositeOperator) -> Self {
match operator {
CompositeOperator::Over => CompositeOperatorKey::Over,
CompositeOperator::In => CompositeOperatorKey::In,
CompositeOperator::Out => CompositeOperatorKey::Out,
CompositeOperator::Atop => CompositeOperatorKey::Atop,
CompositeOperator::Xor => CompositeOperatorKey::Xor,
CompositeOperator::Lighter => CompositeOperatorKey::Lighter,
CompositeOperator::Arithmetic(k_vals) => {
let k_vals = [
Au::from_f32_px(k_vals[0]),
Au::from_f32_px(k_vals[1]),
Au::from_f32_px(k_vals[2]),
Au::from_f32_px(k_vals[3]),
];
CompositeOperatorKey::Arithmetic(k_vals)
}
}
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, Clone, MallocSizeOf, PartialEq, Hash, Eq)]
@ -32,6 +67,7 @@ pub enum FilterPrimitiveKey {
DropShadow(ColorSpace, (VectorKey, Au, ColorU), FilterPrimitiveInput),
ComponentTransfer(ColorSpace, FilterPrimitiveInput, Vec<SFilterData>),
Offset(ColorSpace, FilterPrimitiveInput, VectorKey),
Composite(ColorSpace, FilterPrimitiveInput, FilterPrimitiveInput, CompositeOperatorKey),
}
/// Represents a hashable description of how a picture primitive
@ -178,6 +214,8 @@ impl From<Option<PictureCompositeMode>> for PictureCompositeKey {
FilterPrimitiveKey::ComponentTransfer(primitive.color_space, component_transfer.input, filter_data.clone()),
FilterPrimitiveKind::Offset(info) =>
FilterPrimitiveKey::Offset(primitive.color_space, info.input, info.offset.into()),
FilterPrimitiveKind::Composite(info) =>
FilterPrimitiveKey::Composite(primitive.color_space, info.input1, info.input2, info.operator.into()),
}
}).collect())
}

View File

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{ImageDescriptor, FilterPrimitive, FilterPrimitiveInput, FilterPrimitiveKind};
use api::{CompositeOperator, ImageDescriptor, FilterPrimitive, FilterPrimitiveInput, FilterPrimitiveKind};
use api::{LineStyle, LineOrientation, ClipMode, DirtyRect, MixBlendMode, ColorF, ColorSpace};
use api::units::*;
use crate::border::BorderSegmentCacheKey;
@ -642,6 +642,7 @@ pub enum SvgFilterInfo {
DropShadow(ColorF),
Offset(DeviceVector2D),
ComponentTransfer(SFilterData),
Composite(CompositeOperator),
// TODO: This is used as a hack to ensure that a blur task's input is always in the blur's previous pass.
Identity,
}
@ -1496,6 +1497,34 @@ impl RenderTask {
);
render_tasks.add(offset_task)
}
FilterPrimitiveKind::Composite(info) => {
let input_1_task_id = get_task_input(
&info.input1,
filter_primitives,
render_tasks,
cur_index,
&outputs,
original_task_id,
primitive.color_space
);
let input_2_task_id = get_task_input(
&info.input2,
filter_primitives,
render_tasks,
cur_index,
&outputs,
original_task_id,
primitive.color_space
);
let task = RenderTask::new_svg_filter_primitive(
vec![input_1_task_id, input_2_task_id],
content_size,
uv_rect_kind,
SvgFilterInfo::Composite(info.operator),
);
render_tasks.add(task)
}
};
outputs.push(render_task_id);
}
@ -1842,6 +1871,14 @@ impl RenderTask {
data.update(request);
}
}
SvgFilterInfo::Composite(ref operator) => {
if let CompositeOperator::Arithmetic(k_vals) = operator {
let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(|| GpuCacheHandle::new());
if let Some(mut request) = gpu_cache.request(handle) {
request.push(*k_vals);
}
}
}
_ => {},
}
}

View File

@ -1502,6 +1502,7 @@ impl SvgFilterTask {
SvgFilterInfo::Offset(..) => 7,
SvgFilterInfo::ComponentTransfer(..) => 8,
SvgFilterInfo::Identity => 9,
SvgFilterInfo::Composite(..) => 10,
};
let input_count = match filter {
@ -1517,7 +1518,8 @@ impl SvgFilterTask {
// Not techincally a 2 input filter, but we have 2 inputs here: original content & blurred content.
SvgFilterInfo::DropShadow(..) |
SvgFilterInfo::Blend(..) => 2,
SvgFilterInfo::Blend(..) |
SvgFilterInfo::Composite(..) => 2,
};
let generic_int = match filter {
@ -1527,7 +1529,8 @@ impl SvgFilterTask {
data.g_func.to_int() << 8 |
data.b_func.to_int() << 4 |
data.a_func.to_int()) as u16),
SvgFilterInfo::Composite(operator) =>
operator.as_int() as u16,
SvgFilterInfo::LinearToSrgb |
SvgFilterInfo::SrgbToLinear |
SvgFilterInfo::Flood(..) |

View File

@ -723,7 +723,6 @@ pub enum MixBlendMode {
Luminosity = 15,
}
/// An input to a SVG filter primitive.
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
pub enum ColorSpace {
@ -731,6 +730,35 @@ pub enum ColorSpace {
LinearRgb,
}
/// Available composite operoations for the composite filter primitive
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
pub enum CompositeOperator {
Over,
In,
Atop,
Out,
Xor,
Lighter,
Arithmetic([f32; 4]),
}
impl CompositeOperator {
// This must stay in sync with the composite operator defines in cs_svg_filter.glsl
pub fn as_int(&self) -> u32 {
match self {
CompositeOperator::Over => 0,
CompositeOperator::In => 1,
CompositeOperator::Out => 2,
CompositeOperator::Atop => 3,
CompositeOperator::Xor => 4,
CompositeOperator::Lighter => 5,
CompositeOperator::Arithmetic(..) => 6,
}
}
}
/// An input to a SVG filter primitive.
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
pub enum FilterPrimitiveInput {
@ -844,6 +872,14 @@ pub struct OffsetPrimitive {
pub offset: LayoutVector2D,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
pub struct CompositePrimitive {
pub input1: FilterPrimitiveInput,
pub input2: FilterPrimitiveInput,
pub operator: CompositeOperator,
}
/// See: https://github.com/eqrion/cbindgen/issues/9
/// cbindgen:derive-eq=false
#[repr(C)]
@ -860,6 +896,7 @@ pub enum FilterPrimitiveKind {
DropShadow(DropShadowPrimitive),
ComponentTransfer(ComponentTransferPrimitive),
Offset(OffsetPrimitive),
Composite(CompositePrimitive),
}
impl Default for FilterPrimitiveKind {
@ -881,6 +918,7 @@ impl FilterPrimitiveKind {
FilterPrimitiveKind::Blend(..) |
FilterPrimitiveKind::ColorMatrix(..) |
FilterPrimitiveKind::Offset(..) |
FilterPrimitiveKind::Composite(..) |
// Component transfer's filter data is sanitized separately.
FilterPrimitiveKind::ComponentTransfer(..) => {}
}
@ -1429,5 +1467,6 @@ impl_default_for_enums! {
YuvData => NV12(ImageKey::default(), ImageKey::default()),
YuvFormat => NV12,
FilterPrimitiveInput => Original,
ColorSpace => Srgb
ColorSpace => Srgb,
CompositeOperator => Over
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,17 @@
# Bug 1561447: If a clip task is created for a picture, it should take into account the rect of the drop shadow
---
root:
items:
- type: clip
id: 2
bounds: 10 0 300 300
clip-rect: 10 0 300 300
- type: stacking-context
bounds: 30 30 0 0
transform: rotate-z(45)
filters: drop-shadow([15, 0], 0, red)
clip-node: 2
items:
- type: rect
bounds: 0 0 100 100
color: blue

View File

@ -35,6 +35,7 @@ platform(linux,mac) == filter-drop-shadow.yaml filter-drop-shadow.png
platform(linux,mac) == filter-drop-shadow-on-viewport-edge.yaml filter-drop-shadow-on-viewport-edge.png
platform(linux,mac) == blend-clipped.yaml blend-clipped.png
platform(linux,mac) == filter-drop-shadow-clip.yaml filter-drop-shadow-clip.png
platform(linux,mac) == filter-drop-shadow-clip-2.yaml filter-drop-shadow-clip-2.png
== filter-segments.yaml filter-segments-ref.yaml
== iframe-dropshadow.yaml iframe-dropshadow-ref.yaml
skip_on(android) == filter-mix-blend-mode.yaml filter-mix-blend-mode-ref.yaml # Android debug: GL error 502 at blit_framebuffer (emulator) or draw_elements_instanced (Pixel2); Android opt: fails
@ -59,3 +60,4 @@ platform(linux,mac) == svg-filter-drop-shadow-perspective.yaml svg-filter-drop-s
== backdrop-filter-basic.yaml backdrop-filter-basic-ref.yaml
platform(linux,mac) == backdrop-filter-perspective.yaml backdrop-filter-perspective.png
platform(linux,max) == svg-filter-offset.yaml svg-filter-offset-ref.yaml
skip_on(android) == fuzzy(1,100) svg-filter-composite.yaml svg-filter-composite-ref.yaml

View File

@ -0,0 +1,73 @@
# Tests the composite SVG filter primitive
---
root:
items:
- type: stacking-context
bounds: 0 0 0 0
items:
- type: rect
color: yellow
bounds: 10 10 100 100
- type: rect
color: blue
bounds: 60 60 100 100
- type: stacking-context
bounds: 200 0 0 0
items:
- type: rect
color: blue
bounds: 60 60 50 50
- type: stacking-context
bounds: 400 0 0 0
items:
- type: rect
color: yellow
bounds: 10 10 100 100
- type: rect
color: blue
bounds: 60 60 50 50
- type: stacking-context
bounds: 600 0 0 0
items:
- type: rect
color: blue
bounds: 60 60 100 100
- type: rect
color: white
bounds: 60 60 50 50
- type: stacking-context
bounds: 0 200 0 0
items:
- type: rect
color: yellow
bounds: 10 10 100 100
- type: rect
color: blue
bounds: 60 60 100 100
- type: rect
color: white
bounds: 60 60 50 50
- type: stacking-context
bounds: 200 200 0 0
items:
- type: rect
color: [255, 0, 0, 1.0]
bounds: 10 10 100 100
- type: rect
color: [0, 0, 255, 1.0]
bounds: 60 60 100 100
- type: rect
color: [255, 0, 255, 1.0]
bounds: 60 60 50 50
- type: stacking-context
bounds: 400 200 0 0
items:
- type: rect
color: [255, 255, 127, 1.0]
bounds: 10 10 100 100
- type: rect
color: [127, 127, 255, 1.0]
bounds: 60 60 100 100
- type: rect
color: [188, 188, 188, 1.0]
bounds: 60 60 50 50

View File

@ -0,0 +1,124 @@
# Tests the composite SVG filter primitive
---
root:
items:
- type: stacking-context
bounds: 0 0 0 0
filter-primitives:
- type: flood
color: yellow
in: previous
- type: offset
offset: -50 -50
in: previous
- type: composite
in1: original
in2: 1
operator: over
items:
- type: rect
color: blue
bounds: 60 60 100 100
- type: stacking-context
bounds: 200 0 0 0
filter-primitives:
- type: flood
color: yellow
in: previous
- type: offset
offset: -50 -50
in: previous
- type: composite
in1: original
in2: 1
operator: in
items:
- type: rect
color: blue
bounds: 60 60 100 100
- type: stacking-context
bounds: 400 0 0 0
filter-primitives:
- type: flood
color: yellow
in: previous
- type: offset
offset: -50 -50
in: previous
- type: composite
in1: original
in2: 1
operator: atop
items:
- type: rect
color: blue
bounds: 60 60 100 100
- type: stacking-context
bounds: 600 0 0 0
filter-primitives:
- type: flood
color: yellow
in: previous
- type: offset
offset: -50 -50
in: previous
- type: composite
in1: original
in2: 1
operator: out
items:
- type: rect
color: blue
bounds: 60 60 100 100
- type: stacking-context
bounds: 0 200 0 0
filter-primitives:
- type: flood
color: yellow
in: previous
- type: offset
offset: -50 -50
in: previous
- type: composite
in1: original
in2: 1
operator: xor
items:
- type: rect
color: blue
bounds: 60 60 100 100
- type: stacking-context
bounds: 200 200 0 0
filter-primitives:
- type: flood
color: [255, 0, 0, 1.0]
in: previous
- type: offset
offset: -50 -50
in: previous
- type: composite
in1: original
in2: 1
operator: lighter
items:
- type: rect
color: [0, 0, 255, 1.0]
bounds: 60 60 100 100
- type: stacking-context
bounds: 400 200 0 0
filter-primitives:
- type: flood
color: yellow
in: previous
- type: offset
offset: -50 -50
in: previous
- type: composite
in1: original
in2: 1
operator: arithmetic
k-values: [0.5, 0.5, 0.5, 0]
items:
- type: rect
color: blue
bounds: 60 60 100 100

View File

@ -404,6 +404,26 @@ fn write_filter_primitives(
filter_input_node(&mut table, "in", info.input);
vector_node(&mut table, "offset", &info.offset);
}
FilterPrimitiveKind::Composite(info) => {
yaml_node(&mut table, "type", Yaml::String("composite".into()));
filter_input_node(&mut table, "in1", info.input1);
filter_input_node(&mut table, "in2", info.input2);
let operator = match info.operator {
CompositeOperator::Over => "over",
CompositeOperator::In => "in",
CompositeOperator::Out => "out",
CompositeOperator::Atop => "atop",
CompositeOperator::Xor => "xor",
CompositeOperator::Lighter => "lighter",
CompositeOperator::Arithmetic(..) => "arithmetic",
};
str_node(&mut table, "operator", operator);
if let CompositeOperator::Arithmetic(k_vals) = info.operator {
f32_vec_node(&mut table, "k-values", &k_vals);
}
}
}
enum_node(&mut table, "color-space", filter_primitive.color_space);
filter_primitives.push(Yaml::Hash(table));

View File

@ -775,6 +775,28 @@ impl YamlHelper for Yaml {
offset: self["offset"].as_vector().unwrap(),
})
}
"composite" => {
let operator = match self["operator"].as_str().unwrap() {
"over" => CompositeOperator::Over,
"in" => CompositeOperator::In,
"out" => CompositeOperator::Out,
"atop" => CompositeOperator::Atop,
"xor" => CompositeOperator::Xor,
"lighter" => CompositeOperator::Lighter,
"arithmetic" => {
let k_vals = self["k-values"].as_vec_f32().unwrap();
assert!(k_vals.len() == 4, "Must be 4 k values for arithmetic composite operator");
let k_vals = [k_vals[0], k_vals[1], k_vals[2], k_vals[3]];
CompositeOperator::Arithmetic(k_vals)
}
_ => panic!("Invalid composite operator"),
};
FilterPrimitiveKind::Composite(CompositePrimitive {
input1: self["in1"].as_filter_input().unwrap(),
input2: self["in2"].as_filter_input().unwrap(),
operator,
})
}
_ => return None,
};

View File

@ -32,3 +32,6 @@ Rust
For Rust Mozilla provides a crate `fluent-locale`_ which implements the concepts described
above.
.. _Intl.Locale: https://bugzilla.mozilla.org/show_bug.cgi?id=1433303
.. _fluent-locale: https://docs.rs/fluent-locale/

View File

@ -1,25 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
Library('plugin-container')
SOURCES += [
'plugin-container.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
if CONFIG['OS_ARCH'] == 'WINNT':
LOCAL_INCLUDES += [
'/toolkit/xre',
'/xpcom/base',
]
if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
LOCAL_INCLUDES += [
'/security/sandbox/chromium',
'/security/sandbox/chromium-shim',
]

View File

@ -12,9 +12,6 @@ DIRS += [
'testshell',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android':
DIRS += ['contentproc']
if CONFIG['OS_ARCH'] == 'WINNT':
DIRS += ['mscom']

View File

@ -59,7 +59,7 @@ namespace {
static const char kDefaultRuntimeScriptFilename[] = "xpcshell.js";
inline XPCShellEnvironment* Environment(Handle<JSObject*> global) {
inline XPCShellEnvironment* Environment(JS::Handle<JSObject*> global) {
AutoJSAPI jsapi;
if (!jsapi.Init(global)) {
return nullptr;

View File

@ -306,7 +306,7 @@ class Nursery {
// Register a malloced buffer that is held by a nursery object, which
// should be freed at the end of a minor GC. Buffers are unregistered when
// their owning objects are tenured.
bool registerMallocedBuffer(void* buffer);
MOZ_MUST_USE bool registerMallocedBuffer(void* buffer);
// Mark a malloced buffer as no longer needing to be freed.
void removeMallocedBuffer(void* buffer) {

View File

@ -47,9 +47,6 @@ for stlfile in ['jsdate.*', 'jsnum.*']:
with Files('builtin/intl/*'):
BUG_COMPONENT = component_intl
if CONFIG['JS_BUNDLED_EDITLINE']:
DIRS += ['editline']
if not CONFIG['JS_DISABLE_SHELL']:
DIRS += ['shell']

View File

@ -7,6 +7,7 @@
if CONFIG['JS_SHELL_NAME']:
GeckoProgram(CONFIG['JS_SHELL_NAME'], linkage=None)
if CONFIG['JS_BUNDLED_EDITLINE']:
DIRS += ['../editline']
USE_LIBS += ['editline']
USE_LIBS += ['static:js']

View File

@ -549,6 +549,27 @@ JSFlatString* JSRope::flattenInternal(JSContext* maybecx) {
wholeChars = const_cast<CharT*>(left.nonInlineChars<CharT>(nogc));
wholeCapacity = capacity;
// registerMallocedBuffer is fallible, so attempt it first before doing
// anything irreversible.
Nursery& nursery = runtimeFromMainThread()->gc.nursery();
bool inTenured = !bufferIfNursery;
if (!inTenured && left.isTenured()) {
// tenured leftmost child is giving its chars buffer to the
// nursery-allocated root node.
if (!nursery.registerMallocedBuffer(wholeChars)) {
if (maybecx) {
ReportOutOfMemory(maybecx);
}
return nullptr;
}
// leftmost child -> root is a tenured -> nursery edge.
bufferIfNursery->putWholeCell(&left);
} else if (inTenured && !left.isTenured()) {
// leftmost child is giving its nursery-held chars buffer to a
// tenured string.
nursery.removeMallocedBuffer(wholeChars);
}
/*
* Simulate a left-most traversal from the root to leftMost->leftChild()
* via first_visit_node
@ -586,19 +607,6 @@ JSFlatString* JSRope::flattenInternal(JSContext* maybecx) {
left.setLengthAndFlags(left_len, DEPENDENT_FLAGS | LATIN1_CHARS_BIT);
}
left.d.s.u3.base = (JSLinearString*)this; /* will be true on exit */
Nursery& nursery = runtimeFromMainThread()->gc.nursery();
bool inTenured = !bufferIfNursery;
if (!inTenured && left.isTenured()) {
// tenured leftmost child is giving its chars buffer to the
// nursery-allocated root node.
nursery.registerMallocedBuffer(wholeChars);
// leftmost child -> root is a tenured -> nursery edge.
bufferIfNursery->putWholeCell(&left);
} else if (inTenured && !left.isTenured()) {
// leftmost child is giving its nursery-held chars buffer to a
// tenured string.
nursery.removeMallocedBuffer(wholeChars);
}
goto visit_right_child;
}
}

View File

@ -2280,6 +2280,23 @@ static bool DecodeStartSection(Decoder& d, ModuleEnvironment* env) {
return d.finishSection(*range, "start");
}
static inline ElemSegment::Kind NormalizeElemSegmentKind(
ElemSegmentKind decodedKind) {
switch (decodedKind) {
case ElemSegmentKind::Active:
case ElemSegmentKind::ActiveWithIndex: {
return ElemSegment::Kind::Active;
}
case ElemSegmentKind::Passive: {
return ElemSegment::Kind::Passive;
}
case ElemSegmentKind::Declared: {
return ElemSegment::Kind::Declared;
}
}
MOZ_CRASH("unexpected elem segment kind");
}
static bool DecodeElemSection(Decoder& d, ModuleEnvironment* env) {
MaybeSectionRange range;
if (!d.startSection(SectionId::Elem, env, &range, "elem")) {
@ -2319,24 +2336,7 @@ static bool DecodeElemSection(Decoder& d, ModuleEnvironment* env) {
}
ElemSegmentKind kind = flags->kind();
switch (kind) {
case ElemSegmentKind::Active:
case ElemSegmentKind::ActiveWithIndex: {
seg->kind = ElemSegment::Kind::Active;
break;
}
case ElemSegmentKind::Passive: {
seg->kind = ElemSegment::Kind::Passive;
break;
}
case ElemSegmentKind::Declared: {
seg->kind = ElemSegment::Kind::Declared;
break;
}
default:
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE();
}
seg->kind = NormalizeElemSegmentKind(kind);
if (kind == ElemSegmentKind::Active ||
kind == ElemSegmentKind::ActiveWithIndex) {

View File

@ -33,8 +33,11 @@ class SandboxPrivate : public nsIGlobalObject,
// The type used to cast to void needs to match the one in GetPrivate.
nsIScriptObjectPrincipal* sop =
static_cast<nsIScriptObjectPrincipal*>(sbp.forget().take());
mozilla::RecordReplayRegisterDeferredFinalizeThing(nullptr, nullptr, sop);
JS_SetPrivate(global, sop);
// Never collect the global while recording or replaying, so that the
// principal reference is not released at a non-deterministic point.
mozilla::recordreplay::HoldJSObject(global);
}
static SandboxPrivate* GetPrivate(JSObject* obj) {

View File

@ -486,8 +486,6 @@ XPCWrappedNative::XPCWrappedNative(already_AddRefed<nsISupports>&& aIdentity,
MOZ_ASSERT(NS_IsMainThread());
mIdentity = aIdentity;
RecordReplayRegisterDeferredFinalizeThing(nullptr, nullptr, mIdentity);
mFlatJSObject.setFlags(FLAT_JS_OBJECT_VALID);
MOZ_ASSERT(mMaybeProto, "bad ctor param");
@ -503,8 +501,6 @@ XPCWrappedNative::XPCWrappedNative(already_AddRefed<nsISupports>&& aIdentity,
MOZ_ASSERT(NS_IsMainThread());
mIdentity = aIdentity;
RecordReplayRegisterDeferredFinalizeThing(nullptr, nullptr, mIdentity);
mFlatJSObject.setFlags(FLAT_JS_OBJECT_VALID);
MOZ_ASSERT(aScope, "bad ctor param");
@ -526,13 +522,8 @@ void XPCWrappedNative::Destroy() {
#endif
if (mIdentity) {
// Either release mIdentity immediately or defer the release. When
// recording or replaying the release must always be deferred, so that
// DeferredFinalize matches the earlier call to
// RecordReplayRegisterDeferredFinalizeThing.
XPCJSRuntime* rt = GetRuntime();
if ((rt && rt->GetDoingFinalization()) ||
recordreplay::IsRecordingOrReplaying()) {
if (rt && rt->GetDoingFinalization()) {
DeferredFinalize(mIdentity.forget().take());
} else {
mIdentity = nullptr;
@ -555,6 +546,10 @@ inline void XPCWrappedNative::SetFlatJSObject(JSObject* object) {
mFlatJSObject = object;
mFlatJSObject.setFlags(FLAT_JS_OBJECT_VALID);
// Never collect the wrapper object while recording or replaying, to avoid
// non-deterministically releasing references during finalization.
recordreplay::HoldJSObject(object);
}
inline void XPCWrappedNative::UnsetFlatJSObject() {
@ -762,10 +757,8 @@ void XPCWrappedNative::FlatJSObjectFinalized() {
}
// We also need to release any native pointers held...
// As for XPCWrappedNative::Destroy, when recording or replaying the
// release must always be deferred.
RefPtr<nsISupports> native = to->TakeNative();
if (native && (GetRuntime() || recordreplay::IsRecordingOrReplaying())) {
if (native && GetRuntime()) {
DeferredFinalize(native.forget().take());
}
@ -1033,7 +1026,6 @@ nsresult XPCWrappedNative::InitTearOff(JSContext* cx,
aTearOff->SetInterface(aInterface);
aTearOff->SetNative(qiResult);
RecordReplayRegisterDeferredFinalizeThing(nullptr, nullptr, qiResult);
if (needJSObject && !InitTearOffJSObject(cx, aTearOff)) {
return NS_ERROR_OUT_OF_MEMORY;

View File

@ -28,8 +28,6 @@ XPCWrappedNativeProto::XPCWrappedNativeProto(
#ifdef DEBUG
gDEBUG_LiveProtoCount++;
#endif
RecordReplayRegisterDeferredFinalizeThing(nullptr, nullptr, mClassInfo);
}
XPCWrappedNativeProto::~XPCWrappedNativeProto() {
@ -57,6 +55,10 @@ bool XPCWrappedNativeProto::Init(JSContext* cx, nsIXPCScriptable* scriptable) {
bool success = !!mJSProtoObject;
if (success) {
JS_SetPrivate(mJSProtoObject, this);
// Never collect the proto object while recording or replaying, to avoid
// non-deterministically releasing references during finalization.
recordreplay::HoldJSObject(mJSProtoObject);
}
return success;

View File

@ -10,6 +10,7 @@
#include "mozilla/gfx/2D.h"
#include "mozilla/PresShell.h"
#include "mozilla/RefPtr.h"
#include "mozilla/StaticPrefs_mathml.h"
#include "nsLayoutUtils.h"
#include "nsPresContext.h"
#include "nsDisplayList.h"
@ -103,28 +104,38 @@ nscoord nsMathMLmfracFrame::CalcLineThickness(nsPresContext* aPresContext,
// default: medium
//
if (!aThicknessAttribute.IsEmpty()) {
if (aThicknessAttribute.EqualsLiteral("thin")) {
lineThickness = NSToCoordFloor(defaultThickness * THIN_FRACTION_LINE);
minimumThickness = onePixel * THIN_FRACTION_LINE_MINIMUM_PIXELS;
// should visually decrease by at least one pixel, if default is not a
// pixel
if (defaultThickness > onePixel &&
lineThickness > defaultThickness - onePixel)
lineThickness = defaultThickness - onePixel;
} else if (aThicknessAttribute.EqualsLiteral("medium")) {
// medium is default
} else if (aThicknessAttribute.EqualsLiteral("thick")) {
lineThickness = NSToCoordCeil(defaultThickness * THICK_FRACTION_LINE);
minimumThickness = onePixel * THICK_FRACTION_LINE_MINIMUM_PIXELS;
// should visually increase by at least one pixel
if (lineThickness < defaultThickness + onePixel)
lineThickness = defaultThickness + onePixel;
} else {
if (StaticPrefs::mathml_mfrac_linethickness_names_disabled()) {
// length value
lineThickness = defaultThickness;
ParseNumericValue(aThicknessAttribute, &lineThickness,
nsMathMLElement::PARSE_ALLOW_UNITLESS, aPresContext,
aComputedStyle, aFontSizeInflation);
} else {
if (aThicknessAttribute.EqualsLiteral("thin")) {
lineThickness = NSToCoordFloor(defaultThickness * THIN_FRACTION_LINE);
minimumThickness = onePixel * THIN_FRACTION_LINE_MINIMUM_PIXELS;
// should visually decrease by at least one pixel, if default is not a
// pixel
if (defaultThickness > onePixel &&
lineThickness > defaultThickness - onePixel) {
lineThickness = defaultThickness - onePixel;
}
} else if (aThicknessAttribute.EqualsLiteral("medium")) {
// medium is default
} else if (aThicknessAttribute.EqualsLiteral("thick")) {
lineThickness = NSToCoordCeil(defaultThickness * THICK_FRACTION_LINE);
minimumThickness = onePixel * THICK_FRACTION_LINE_MINIMUM_PIXELS;
// should visually increase by at least one pixel
if (lineThickness < defaultThickness + onePixel) {
lineThickness = defaultThickness + onePixel;
}
} else {
// length value
lineThickness = defaultThickness;
ParseNumericValue(aThicknessAttribute, &lineThickness,
nsMathMLElement::PARSE_ALLOW_UNITLESS, aPresContext,
aComputedStyle, aFontSizeInflation);
}
}
}

View File

@ -52,10 +52,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=553917
<math><mspace width="2"/></math>
<math><mo lspace="BADlspace">+</mo></math>
<math><mspace height="BADheight"/></math>
<math><mspace depth="BADdepth"/></math>*/
<math><mspace depth="BADdepth"/></math>
<math><mfrac linethickness="thin"><mn>1</mn><mn>2</mn></mfrac></math>
<math><mfrac linethickness="medium"><mn>1</mn><mn>2</mn></mfrac></math>
<math><mfrac linethickness="thick"><mn>1</mn><mn>2</mn></mfrac></math>
*/
LengthParsingError : {
status: [false, false, false, false, false, false],
args: [["2..0"], ["1.5notaunit"], ["2"],["BADlspace"],["BADheight"],["BADdepth"]]
status: [false, false, false, false, false, false, false, false, false],
args: [["2..0"], ["1.5notaunit"], ["2"],["BADlspace"],["BADheight"],["BADdepth"], ["thin"],["medium"],["thick"]]
},
/*<math><mmultiscripts></mmultiscripts></math>
<math><mmultiscripts><mprescripts/><mprescripts/></mmultiscripts></math>
@ -157,6 +161,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=553917
<math><mo lspace="BADlspace">+</mo></math>
<math><mspace height="BADheight"/></math>
<math><mspace depth="BADdepth"/></math>
<math><mfrac linethickness="thin"><mn>1</mn><mn>2</mn></mfrac></math>
<math><mfrac linethickness="medium"><mn>1</mn><mn>2</mn></mfrac></math>
<math><mfrac linethickness="thick"><mn>1</mn><mn>2</mn></mfrac></math>
<!-- MMultiscriptsErrors -->
<math><mmultiscripts></mmultiscripts></math>

View File

@ -0,0 +1 @@
<u>🏴󠁵󠁳󠁣󠁡󠁿</u>

View File

@ -21,4 +21,4 @@ load 1547420-1.html
load 1549909.html
asserts(6) load 1551389-1.html # bug 847368
asserts(0-2) load 1555819-1.html
load 1574392.html

View File

@ -3877,7 +3877,10 @@ static sk_sp<const SkTextBlob> CreateTextBlob(
// allocate space for the run buffer, then fill it with the glyphs
uint32_t len =
CountAllGlyphs(aTextRun, aCompressedGlyph, aStringStart, aStringEnd);
MOZ_ASSERT(len > 0, "there must be at least one glyph for skip ink");
if (len <= 0) {
return nullptr;
}
SkTextBlobBuilder builder;
const SkTextBlobBuilder::RunBuffer& run = builder.allocRunPos(aFont, len);
@ -4116,6 +4119,10 @@ void nsCSSRendering::PaintDecorationLine(
iter.GetStringStart(), iter.GetStringEnd(),
(float)appUnitsPerDevPixel, textPos, spacingOffset);
if (!textBlob) {
continue;
}
if (textRun->UseCenterBaseline()) {
// writing modes that use a center baseline need to be adjusted on a
// font-by-font basis since Skia lines up the text on a alphabetic

Binary file not shown.

View File

@ -38,7 +38,7 @@
<tr>
<td>mfrac: bevelled, linethickness</td>
<td><math xmlns="http://www.w3.org/1998/Math/MathML">
<mstyle bevelled="true" linethickness="thick">
<mstyle bevelled="true" linethickness="10px">
<mfrac>
<mi>a</mi>
<mi>b</mi>

View File

@ -149,7 +149,7 @@ random-if(gtkWidget) == mpadded-9.html mpadded-9-ref.html # bug 1309430
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == munderover-align-accent-true.html munderover-align-accent-true-ref.html # Bug 1392106
== munder-mover-align-accent-true.html munder-mover-align-accent-true-ref.html
== munder-mover-align-accent-false.html munder-mover-align-accent-false-ref.html
== mfrac-linethickness-1.xhtml mfrac-linethickness-1-ref.xhtml
pref(mathml.mfrac_linethickness_names.disabled,false) == mfrac-linethickness-1.xhtml mfrac-linethickness-1-ref.xhtml
== mfrac-linethickness-2.xhtml mfrac-linethickness-2-ref.xhtml
== mfrac-linethickness-3.xhtml mfrac-linethickness-3-ref.xhtml
== mathml-negativespace.html mathml-negativespace-ref.html
@ -341,23 +341,23 @@ random-if(gtkWidget) == rowlines-3-2.html rowlines-3-2-ref.html # bug 1309426
== mfrac-A-2.html mfrac-A-2-ref.html
== mfrac-A-3.html mfrac-A-3-ref.html
== mfrac-A-4.html mfrac-A-4-ref.html
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == mfrac-A-5.html mfrac-A-5-ref.html # bug 1309426
pref(mathml.mfrac_linethickness_names.disabled,false) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == mfrac-A-5.html mfrac-A-5-ref.html # bug 1309426
== mfrac-A-6.html mfrac-A-6-ref.html
== mfrac-A-7.html mfrac-A-7-ref.html
== mfrac-A-8.html mfrac-A-8-ref.html
== mfrac-B-1.html mfrac-B-1-ref.html
== mfrac-B-2.html mfrac-B-2-3-ref.html
== mfrac-B-3.html mfrac-B-2-3-ref.html
pref(mathml.mfrac_linethickness_names.disabled,false) == mfrac-B-2.html mfrac-B-2-3-ref.html
pref(mathml.mfrac_linethickness_names.disabled,false) == mfrac-B-3.html mfrac-B-2-3-ref.html
fuzzy-if(geckoview&&webrender,0-198,0-781) == mfrac-B-4.html mfrac-B-4-5-ref.html
== mfrac-B-5.html mfrac-B-4-5-ref.html
fuzzy-if(geckoview&&webrender,0-198,0-781) == mfrac-B-6.html mfrac-B-6-7-ref.html
== mfrac-B-7.html mfrac-B-6-7-ref.html
fuzzy-if(OSX,0-1,0-100) fuzzy-if(skiaContent,0-1,0-14) == mfrac-C-1.html mfrac-C-1-ref.html
== mfrac-C-2.html mfrac-C-2-ref.html
pref(mathml.mfrac_linethickness_names.disabled,false) == mfrac-C-2.html mfrac-C-2-ref.html
fuzzy-if(geckoview&&webrender,0-198,0-776) == mfrac-C-3.html mfrac-C-3-ref.html
fuzzy-if(geckoview&&webrender,0-198,0-270) == mfrac-C-4.html mfrac-C-4-ref.html
fuzzy-if(OSX,0-1,0-100) fuzzy-if(skiaContent,0-1,0-14) == mfrac-D-1.html mfrac-D-1-ref.html
== mfrac-D-2.html mfrac-D-2-ref.html
pref(mathml.mfrac_linethickness_names.disabled,false) == mfrac-D-2.html mfrac-D-2-ref.html
fuzzy-if(geckoview&&webrender,0-198,0-776) == mfrac-D-3.html mfrac-D-3-ref.html
fuzzy-if(geckoview&&webrender,0-198,0-270) == mfrac-D-4.html mfrac-D-4-ref.html
== mfrac-E-1.html mfrac-E-1-ref.html

View File

@ -114,3 +114,7 @@ fuzzy-if(skiaContent,0-4,0-2) == underline-select-1.html underline-select-1-ref.
fuzzy-if(Android,0-238,0-36) == vertical-mode-decorations-2.html vertical-mode-decorations-2-ref.html
!= 1415214.html 1415214-notref.html
test-pref(layout.css.text-decoration-thickness.enabled,false) == text-decoration-shorthands-001.html text-decoration-shorthands-001-ref.html
# fails because of bug 1572302
test-pref(layout.css.text-decoration-skip-ink.enabled,true) test-pref(layout.css.text-underline-offset.enabled,true) fails HTTP(..) == skip-ink-multiline-position.html skip-ink-multiline-position-ref.html
# fails due to bug 1573711
test-pref(layout.css.text-decoration-skip-ink.enabled,true) fails == skip-ink-vertical-align.html skip-ink-vertical-align-ref.html

View File

@ -0,0 +1,26 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Reference case for text-decoration-skip-ink: text on the second line should not change the position of the first line's underline</title>
<style>
@font-face {
font-family: awami;
src: url("../fonts/AwamiNastaliq-Regular.woff");
}
div{
font: 36px/2 awami, sans-serif;
unicode-bidi:bidi-override;
width: 70px;
height: 70px;
overflow: hidden;
text-decoration: red underline;
text-underline-offset: -0.5em;
}
</style>
</head>
<body>
<p>Adding more characters on the second line should not affect the position of the underline on line one. <br>See <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1572302"> Bug 1572303</a> </p>
<div dir="rtl">fی sعلي</div>
</body>
</html>

View File

@ -0,0 +1,26 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test case for text-decoration-skip-ink: text on the second line should not change the position of the first line's underline</title>
<style>
@font-face {
font-family: awami;
src: url("../fonts/AwamiNastaliq-Regular.woff");
}
div{
font: 36px/2 awami, sans-serif;
unicode-bidi:bidi-override;
width: 70px;
height: 70px;
overflow: hidden;
text-decoration: red underline;
text-underline-offset: -0.5em;
}
</style>
</head>
<body>
<p>Adding more characters on the second line should not affect the position of the underline on line one. <br>See <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1572302"> Bug 1572303</a> </p>
<div dir="rtl">fی علي</div>
</body>
</html>

View File

@ -0,0 +1,20 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Reference case for text-decoration-skip-ink: skip-ink should detect and work with vertical-align</title>
<style>
div{
font: 48px/2 Times;
text-decoration: purple underline;
text-decoration-skip-ink: none;
}
span{
vertical-align: super;
}
</style>
</head>
<body>
<p>Ink should not be skipped when vertical-align moves text away from the underline</p>
<div>test <span>pgqy</span> test</div>
</body>
</html>

View File

@ -0,0 +1,19 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test case for text-decoration-skip-ink: skip-ink should detect and work with vertical-align</title>
<style>
div{
font: 48px/2 Times;
text-decoration: purple underline;
}
span{
vertical-align: super;
}
</style>
</head>
<body>
<p>Ink should not be skipped when vertical-align moves text away from the underline</p>
<div>test <span>pgqy</span> test</div>
</body>
</html>

View File

@ -461,32 +461,11 @@ struct Loader::Sheets {
// The SheetLoadData pointers in mLoadingDatas below are weak references.
nsDataHashtable<SheetLoadDataHashKey, SheetLoadData*> mLoadingDatas;
nsRefPtrHashtable<nsStringHashKey, StyleSheet> mInlineSheets;
RefPtr<StyleSheet> LookupInline(const nsAString&);
// A cache hit or miss. It is a miss if the `StyleSheet` is null.
using CacheResult = Tuple<RefPtr<StyleSheet>, SheetState>;
CacheResult Lookup(SheetLoadDataHashKey&, bool aSyncLoad);
size_t SizeOfIncludingThis(MallocSizeOf) const;
};
RefPtr<StyleSheet> Loader::Sheets::LookupInline(const nsAString& aBuffer) {
auto result = mInlineSheets.Lookup(aBuffer);
if (!result) {
return nullptr;
}
if (result.Data()->HasForcedUniqueInner()) {
// Remove it now that we know that we're never going to use this stylesheet
// again.
result.Remove();
return nullptr;
}
return result.Data()->Clone(nullptr, nullptr, nullptr, nullptr);
}
static void AssertComplete(const StyleSheet& aSheet) {
// This sheet came from the XUL cache or our per-document hashtable; it
// better be a complete sheet.
@ -580,39 +559,6 @@ auto Loader::Sheets::Lookup(SheetLoadDataHashKey& aKey, bool aSyncLoad)
return {};
}
size_t Loader::Sheets::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
size_t n = aMallocSizeOf(this);
n += mCompleteSheets.ShallowSizeOfExcludingThis(aMallocSizeOf);
for (auto iter = mCompleteSheets.ConstIter(); !iter.Done(); iter.Next()) {
// If the sheet has a parent, then its parent will report it so we don't
// have to worry about it here. Likewise, if aSheet has an owning node, then
// the document that node is in will report it.
const StyleSheet* sheet = iter.UserData();
if (!sheet->GetOwnerNode() && !sheet->GetParentSheet()) {
n += sheet->SizeOfIncludingThis(aMallocSizeOf);
}
}
n += mInlineSheets.ShallowSizeOfExcludingThis(aMallocSizeOf);
for (auto iter = mInlineSheets.ConstIter(); !iter.Done(); iter.Next()) {
n += iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
// If the sheet has a parent, then its parent will report it so we don't
// have to worry about it here.
const StyleSheet* sheet = iter.UserData();
MOZ_ASSERT(!sheet->GetParentSheet(), "How did an @import rule end up here?");
if (!sheet->GetOwnerNode()) {
n += sheet->SizeOfIncludingThis(aMallocSizeOf);
}
}
// Measurement of the following members may be added later if DMD finds it is
// worthwhile:
// - mLoadingDatas: transient, and should be small
// - mPendingDatas: transient, and should be small
return n;
}
/*************************
* Loader Implementation *
*************************/
@ -1879,7 +1825,6 @@ Result<Loader::LoadSheetResult, nsresult> Loader::LoadInlineStyle(
// Check IsAlternateSheet now, since it can mutate our document.
auto isAlternate = IsAlternateSheet(aInfo.mTitle, aInfo.mHasAlternateRel);
LOG((" Sheet is alternate: %d", static_cast<int>(isAlternate)));
// Use the document's base URL so that @import in the inline sheet picks up
// the right base.
@ -1888,71 +1833,48 @@ Result<Loader::LoadSheetResult, nsresult> Loader::LoadInlineStyle(
nsIURI* originalURI = nullptr;
MOZ_ASSERT(aInfo.mIntegrity.IsEmpty());
auto sheet = MakeRefPtr<StyleSheet>(eAuthorSheetFeatures, aInfo.mCORSMode,
SRIMetadata{});
sheet->SetURIs(sheetURI, originalURI, baseURI);
nsCOMPtr<nsIReferrerInfo> referrerInfo =
ReferrerInfo::CreateForInternalCSSResources(aInfo.mContent->OwnerDoc());
sheet->SetReferrerInfo(referrerInfo);
// We only cache sheets if in shadow trees, since regular document sheets are
// likely to be unique.
const bool isWorthCaching = aInfo.mContent->IsInShadowTree();
RefPtr<StyleSheet> sheet;
if (isWorthCaching) {
if (!mSheets) {
mSheets = MakeUnique<Sheets>();
}
sheet = mSheets->LookupInline(aBuffer);
nsIPrincipal* principal = aInfo.mContent->NodePrincipal();
if (aInfo.mTriggeringPrincipal) {
// The triggering principal may be an expanded principal, which is safe to
// use for URL security checks, but not as the loader principal for a
// stylesheet. So treat this as principal inheritance, and downgrade if
// necessary.
principal =
BasePrincipal::Cast(aInfo.mTriggeringPrincipal)->PrincipalToInherit();
}
const bool sheetFromCache = !!sheet;
if (!sheet) {
sheet = MakeRefPtr<StyleSheet>(eAuthorSheetFeatures, aInfo.mCORSMode,
SRIMetadata{});
sheet->SetURIs(sheetURI, originalURI, baseURI);
nsCOMPtr<nsIReferrerInfo> referrerInfo =
ReferrerInfo::CreateForInternalCSSResources(aInfo.mContent->OwnerDoc());
sheet->SetReferrerInfo(referrerInfo);
nsIPrincipal* principal = aInfo.mContent->NodePrincipal();
if (aInfo.mTriggeringPrincipal) {
// The triggering principal may be an expanded principal, which is safe to
// use for URL security checks, but not as the loader principal for a
// stylesheet. So treat this as principal inheritance, and downgrade if
// necessary.
principal =
BasePrincipal::Cast(aInfo.mTriggeringPrincipal)->PrincipalToInherit();
}
// We never actually load this, so just set its principal directly
sheet->SetPrincipal(principal);
// We never actually load this, so just set its principal directly
sheet->SetPrincipal(principal);
}
LOG((" Sheet is alternate: %d", static_cast<int>(isAlternate)));
auto matched = PrepareSheet(*sheet, aInfo.mTitle, aInfo.mMedia, nullptr,
isAlternate, aInfo.mIsExplicitlyEnabled);
InsertSheetInTree(*sheet, aInfo.mContent);
Completed completed;
if (sheetFromCache) {
MOZ_ASSERT(sheet->IsComplete());
completed = Completed::Yes;
} else {
auto data = MakeRefPtr<SheetLoadData>(
this, aInfo.mTitle, nullptr, sheet, false, owningElement, isAlternate,
matched, aObserver, nullptr, aInfo.mReferrerInfo, aInfo.mContent);
data->mLineNumber = aLineNumber;
// Parse completion releases the load data.
//
// Note that we need to parse synchronously, since the web expects that the
// effects of inline stylesheets are visible immediately (aside from
// @imports).
NS_ConvertUTF16toUTF8 utf8(aBuffer);
completed = ParseSheet(utf8, *data, AllowAsyncParse::No);
if (completed == Completed::Yes) {
// TODO(emilio): Try to cache sheets with @import rules, maybe?
if (isWorthCaching) {
mSheets->mInlineSheets.Put(aBuffer, sheet);
}
} else {
data->mMustNotify = true;
}
}
auto data = MakeRefPtr<SheetLoadData>(
this, aInfo.mTitle, nullptr, sheet, false, owningElement, isAlternate,
matched, aObserver, nullptr, aInfo.mReferrerInfo, aInfo.mContent);
data->mLineNumber = aLineNumber;
// Parse completion releases the load data.
//
// Note that we need to parse synchronously, since the web expects that the
// effects of inline stylesheets are visible immediately (aside from
// @imports).
NS_ConvertUTF16toUTF8 utf8(aBuffer);
Completed completed = ParseSheet(utf8, *data, AllowAsyncParse::No);
if (completed == Completed::No) {
data->mMustNotify = true;
}
return LoadSheetResult{completed, isAlternate, matched};
}
@ -2475,16 +2397,28 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(Loader, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(Loader, Release)
size_t Loader::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
size_t Loader::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
size_t n = aMallocSizeOf(this);
if (mSheets) {
n += mSheets->SizeOfIncludingThis(aMallocSizeOf);
n += mSheets->mCompleteSheets.ShallowSizeOfExcludingThis(aMallocSizeOf);
for (auto iter = mSheets->mCompleteSheets.ConstIter(); !iter.Done();
iter.Next()) {
// If aSheet has a parent, then its parent will report it so we don't
// have to worry about it here. Likewise, if aSheet has an owning node,
// then the document that node is in will report it.
const StyleSheet* sheet = iter.UserData();
n += (sheet->GetOwnerNode() || sheet->GetParentSheet())
? 0
: sheet->SizeOfIncludingThis(aMallocSizeOf);
}
}
n += mObservers.ShallowSizeOfExcludingThis(aMallocSizeOf);
// Measurement of the following members may be added later if DMD finds it is
// worthwhile:
// - mLoadingDatas: transient, and should be small
// - mPendingDatas: transient, and should be small
// - mPostedEvents: transient, and should be small
//
// The following members aren't measured:

View File

@ -3,4 +3,4 @@ git repository using the update.sh script.
The cubeb-coreaudio-rs git repository is: https://github.com/ChunMinChang/cubeb-coreaudio-rs
The git commit ID used was ee0f9814230f4a236516444eff9406857ab6c70d (2019-08-01 10:57:48 -0700)
The git commit ID used was 71faddb88ad9cdc51147451ebb57316c159278e1 (2019-08-16 08:46:59 -0700)

View File

@ -1,7 +1,11 @@
use core_foundation_sys::base::{kCFAllocatorDefault, kCFAllocatorNull, Boolean, CFIndex};
use core_foundation_sys::base::{
kCFAllocatorDefault, kCFAllocatorNull, Boolean, CFIndex, CFRange, CFRelease,
};
use core_foundation_sys::string::{
kCFStringEncodingUTF8, CFStringCreateWithBytes, CFStringCreateWithBytesNoCopy,
CFStringGetBytes, CFStringGetLength, CFStringRef,
};
use std::ffi::CString;
pub fn cfstringref_from_static_string(string: &'static str) -> coreaudio_sys::CFStringRef {
// Set deallocator to kCFAllocatorNull to prevent the the memory of the parameter `string`
@ -32,11 +36,95 @@ pub fn cfstringref_from_string(string: &str) -> coreaudio_sys::CFStringRef {
cfstringref as coreaudio_sys::CFStringRef
}
#[derive(Debug)]
pub struct StringRef(CFStringRef);
impl StringRef {
pub fn new(string_ref: CFStringRef) -> Self {
assert!(!string_ref.is_null());
Self(string_ref)
}
pub fn to_string(&self) -> String {
String::from_utf8(utf8_from_cfstringref(self.0)).expect("convert bytes to a String")
}
pub fn into_string(self) -> String {
self.to_string()
}
pub fn to_cstring(&self) -> CString {
unsafe {
// Assume that bytes doesn't contain `0` in the middle.
CString::from_vec_unchecked(utf8_from_cfstringref(self.0))
}
}
pub fn into_cstring(self) -> CString {
self.to_cstring()
}
pub fn get_raw(&self) -> CFStringRef {
self.0
}
}
impl Drop for StringRef {
fn drop(&mut self) {
use std::os::raw::c_void;
unsafe { CFRelease(self.0 as *mut c_void) };
}
}
fn utf8_from_cfstringref(string_ref: CFStringRef) -> Vec<u8> {
use std::ptr;
assert!(!string_ref.is_null());
let length: CFIndex = unsafe { CFStringGetLength(string_ref) };
assert!(length > 0);
// Get the buffer size of the string.
let range: CFRange = CFRange {
location: 0,
length,
};
let mut size: CFIndex = 0;
let mut converted_chars: CFIndex = unsafe {
CFStringGetBytes(
string_ref,
range,
kCFStringEncodingUTF8,
0,
false as Boolean,
ptr::null_mut() as *mut u8,
0,
&mut size,
)
};
assert!(converted_chars > 0 && size > 0);
// Then, allocate the buffer with the required size and actually copy data into it.
let mut buffer = vec![b'\x00'; size as usize];
converted_chars = unsafe {
CFStringGetBytes(
string_ref,
range,
kCFStringEncodingUTF8,
0,
false as Boolean,
buffer.as_mut_ptr(),
size,
ptr::null_mut() as *mut CFIndex,
)
};
assert!(converted_chars > 0);
buffer
}
#[cfg(test)]
mod test {
use super::*;
use core_foundation_sys::base::{CFRange, CFRelease};
use core_foundation_sys::string::{CFStringGetBytes, CFStringGetLength, CFStringRef};
const STATIC_STRING: &str = "static string for testing";
@ -44,7 +132,11 @@ mod test {
fn test_create_static_cfstring_ref() {
let stringref =
StringRef::new(cfstringref_from_static_string(STATIC_STRING) as CFStringRef);
assert_eq!(STATIC_STRING, stringref.into_string());
assert_eq!(STATIC_STRING, stringref.to_string());
assert_eq!(
CString::new(STATIC_STRING).unwrap(),
stringref.into_cstring()
);
// TODO: Find a way to check the string's inner pointer is same.
}
@ -52,77 +144,8 @@ mod test {
fn test_create_cfstring_ref() {
let expected = "Rustaceans 🦀";
let stringref = StringRef::new(cfstringref_from_string(expected) as CFStringRef);
assert_eq!(expected, stringref.into_string());
assert_eq!(expected, stringref.to_string());
assert_eq!(CString::new(expected).unwrap(), stringref.into_cstring());
// TODO: Find a way to check the string's inner pointer is different.
}
#[derive(Debug)]
struct StringRef(CFStringRef);
impl StringRef {
fn new(string_ref: CFStringRef) -> Self {
assert!(!string_ref.is_null());
Self(string_ref)
}
fn to_string(&self) -> String {
String::from_utf8(utf8_from_cfstringref(self.0)).unwrap()
}
fn into_string(self) -> String {
self.to_string()
}
}
impl Drop for StringRef {
fn drop(&mut self) {
use std::os::raw::c_void;
unsafe { CFRelease(self.0 as *mut c_void) };
}
}
fn utf8_from_cfstringref(string_ref: CFStringRef) -> Vec<u8> {
use std::ptr;
assert!(!string_ref.is_null());
let length: CFIndex = unsafe { CFStringGetLength(string_ref) };
assert!(length > 0);
let range: CFRange = CFRange {
location: 0,
length,
};
let mut size: CFIndex = 0;
let mut converted_chars: CFIndex = unsafe {
CFStringGetBytes(
string_ref,
range,
kCFStringEncodingUTF8,
0,
false as Boolean,
ptr::null_mut() as *mut u8,
0,
&mut size,
)
};
assert!(converted_chars > 0 && size > 0);
// Then, allocate the buffer with the required size and actually copy data into it.
let mut buffer = vec![b'\x00'; size as usize];
converted_chars = unsafe {
CFStringGetBytes(
string_ref,
range,
kCFStringEncodingUTF8,
0,
false as Boolean,
buffer.as_mut_ptr(),
size,
ptr::null_mut() as *mut CFIndex,
)
};
assert!(converted_chars > 0);
buffer
}
}

View File

@ -2,6 +2,7 @@ use super::*;
use std::time::{SystemTime, UNIX_EPOCH};
const APPLE_EVENT_TIMEOUT: OSStatus = -1712;
pub const DRIFT_COMPENSATION: u32 = 1;
#[derive(Debug)]
pub struct AggregateDevice {
@ -349,17 +350,13 @@ impl AggregateDevice {
// The order of the items in the array is significant and is used to determine the order of the streams
// of the AudioAggregateDevice.
for device in output_sub_devices {
let uid = get_device_name(device);
assert!(!uid.is_null());
CFArrayAppendValue(sub_devices, uid as *const c_void);
CFRelease(uid as *const c_void);
let uid = get_device_global_uid(device)?;
CFArrayAppendValue(sub_devices, uid.get_raw() as *const c_void);
}
for device in input_sub_devices {
let uid = get_device_name(device);
assert!(!uid.is_null());
CFArrayAppendValue(sub_devices, uid as *const c_void);
CFRelease(uid as *const c_void);
let uid = get_device_global_uid(device)?;
CFArrayAppendValue(sub_devices, uid.get_raw() as *const c_void);
}
let address = AudioObjectPropertyAddress {
@ -432,14 +429,10 @@ impl AggregateDevice {
assert_ne!(output_device_id, kAudioObjectUnknown);
let output_sub_devices = Self::get_sub_devices(output_device_id)?;
assert!(!output_sub_devices.is_empty());
let master_sub_device = get_device_name(output_sub_devices[0]);
let master_sub_device_uid = get_device_global_uid(output_sub_devices[0]).unwrap();
let master_sub_device = master_sub_device_uid.get_raw();
let size = mem::size_of::<CFStringRef>();
let status = audio_object_set_property_data(device_id, &address, size, &master_sub_device);
if !master_sub_device.is_null() {
unsafe {
CFRelease(master_sub_device as *const c_void);
}
}
if status == NO_ERR {
Ok(())
} else {
@ -499,12 +492,11 @@ impl AggregateDevice {
// Start from the second device since the first is the master clock
for device in &sub_devices[1..] {
let drift_compensation_value: u32 = 1;
let status = audio_object_set_property_data(
*device,
&address,
mem::size_of::<u32>(),
&drift_compensation_value,
&DRIFT_COMPENSATION,
);
if status != NO_ERR {
cubeb_log!(
@ -555,43 +547,19 @@ impl AggregateDevice {
assert_ne!(output_id, kAudioObjectUnknown);
assert_ne!(input_id, output_id);
let mut input_device_info = ffi::cubeb_device_info::default();
audiounit_create_device_from_hwdev(&mut input_device_info, input_id, DeviceType::INPUT);
let label = get_device_label(input_id, DeviceType::INPUT)?;
let input_label = label.into_string();
let mut output_device_info = ffi::cubeb_device_info::default();
audiounit_create_device_from_hwdev(&mut output_device_info, output_id, DeviceType::OUTPUT);
let label = get_device_label(output_id, DeviceType::OUTPUT)?;
let output_label = label.into_string();
let input_name_str = unsafe {
CString::from_raw(input_device_info.friendly_name as *mut c_char)
.into_string()
.expect("Fail to convert input name from CString into String")
};
input_device_info.friendly_name = ptr::null();
let output_name_str = unsafe {
CString::from_raw(output_device_info.friendly_name as *mut c_char)
.into_string()
.expect("Fail to convert output name from CString into String")
};
output_device_info.friendly_name = ptr::null();
let _teardown = finally(|| {
// Retrieve the rest lost memory.
// No need to retrieve the memory of {input,output}_device_info.friendly_name
// since they are already retrieved/retaken above.
assert!(input_device_info.friendly_name.is_null());
audiounit_device_destroy(&mut input_device_info);
assert!(output_device_info.friendly_name.is_null());
audiounit_device_destroy(&mut output_device_info);
});
if input_name_str.contains("AirPods") && output_name_str.contains("AirPods") {
if input_label.contains("AirPods") && output_label.contains("AirPods") {
let mut input_min_rate = 0;
let mut input_max_rate = 0;
let mut input_nominal_rate = 0;
audiounit_get_available_samplerate(
input_id,
kAudioObjectPropertyScopeGlobal,
DeviceType::INPUT | DeviceType::OUTPUT,
&mut input_min_rate,
&mut input_max_rate,
&mut input_nominal_rate,
@ -599,7 +567,7 @@ impl AggregateDevice {
cubeb_log!(
"Input device {}, name: {}, min: {}, max: {}, nominal rate: {}",
input_id,
input_name_str,
input_label,
input_min_rate,
input_max_rate,
input_nominal_rate
@ -610,7 +578,7 @@ impl AggregateDevice {
let mut output_nominal_rate = 0;
audiounit_get_available_samplerate(
output_id,
kAudioObjectPropertyScopeGlobal,
DeviceType::INPUT | DeviceType::OUTPUT,
&mut output_min_rate,
&mut output_max_rate,
&mut output_nominal_rate,
@ -618,7 +586,7 @@ impl AggregateDevice {
cubeb_log!(
"Output device {}, name: {}, min: {}, max: {}, nominal rate: {}",
output_id,
output_name_str,
output_label,
output_min_rate,
output_max_rate,
output_nominal_rate

View File

@ -133,7 +133,7 @@ fn test_auto_array_impl<T: Clone + Debug + PartialEq + Zero>(buf: &[T]) {
#[cfg(test)]
fn test_auto_array_wrapper<T: Clone + Debug + PartialEq + Zero>(buf: &[T]) {
let mut auto_array: Option<Box<AutoArrayWrapper>> = None;
let mut auto_array: Option<Box<dyn AutoArrayWrapper>> = None;
auto_array = Some(Box::new(AutoArrayImpl::<T>::new(5)));
assert_eq!(auto_array.as_ref().unwrap().elements(), 0);

View File

@ -0,0 +1,159 @@
use super::*;
pub fn get_device_global_uid(id: AudioDeviceID) -> std::result::Result<StringRef, OSStatus> {
get_device_uid(id, DeviceType::INPUT | DeviceType::OUTPUT)
}
pub fn get_device_uid(
id: AudioDeviceID,
devtype: DeviceType,
) -> std::result::Result<StringRef, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
let address = get_property_address(Property::DeviceUID, devtype);
let mut size = mem::size_of::<CFStringRef>();
let mut uid: CFStringRef = ptr::null();
let err = audio_object_get_property_data(id, &address, &mut size, &mut uid);
if err == NO_ERR {
Ok(StringRef::new(uid as _))
} else {
Err(err)
}
}
pub fn get_device_source(
id: AudioDeviceID,
devtype: DeviceType,
) -> std::result::Result<u32, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
let address = get_property_address(Property::DeviceSource, devtype);
let mut size = mem::size_of::<u32>();
let mut source: u32 = 0;
let err = audio_object_get_property_data(id, &address, &mut size, &mut source);
if err == NO_ERR {
Ok(source)
} else {
Err(err)
}
}
pub fn get_device_source_name(
id: AudioDeviceID,
devtype: DeviceType,
) -> std::result::Result<StringRef, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
let mut source: u32 = get_device_source(id, devtype)?;
let address = get_property_address(Property::DeviceSourceName, devtype);
let mut size = mem::size_of::<AudioValueTranslation>();
let mut name: CFStringRef = ptr::null();
let mut trl = AudioValueTranslation {
mInputData: &mut source as *mut u32 as *mut c_void,
mInputDataSize: mem::size_of::<u32>() as u32,
mOutputData: &mut name as *mut CFStringRef as *mut c_void,
mOutputDataSize: mem::size_of::<CFStringRef>() as u32,
};
let err = audio_object_get_property_data(id, &address, &mut size, &mut trl);
if err == NO_ERR {
Ok(StringRef::new(name as _))
} else {
Err(err)
}
}
pub fn get_device_name(
id: AudioDeviceID,
devtype: DeviceType,
) -> std::result::Result<StringRef, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
let address = get_property_address(Property::DeviceName, devtype);
let mut size = mem::size_of::<CFStringRef>();
let mut name: CFStringRef = ptr::null();
let err = audio_object_get_property_data(id, &address, &mut size, &mut name);
if err == NO_ERR {
Ok(StringRef::new(name as _))
} else {
Err(err)
}
}
pub fn get_device_label(
id: AudioDeviceID,
devtype: DeviceType,
) -> std::result::Result<StringRef, OSStatus> {
get_device_source_name(id, devtype).or(get_device_name(id, devtype))
}
pub fn get_device_manufacturer(
id: AudioDeviceID,
devtype: DeviceType,
) -> std::result::Result<StringRef, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
let address = get_property_address(Property::DeviceManufacturer, devtype);
let mut size = mem::size_of::<CFStringRef>();
let mut manufacturer: CFStringRef = ptr::null();
let err = audio_object_get_property_data(id, &address, &mut size, &mut manufacturer);
if err == NO_ERR {
Ok(StringRef::new(manufacturer as _))
} else {
Err(err)
}
}
pub fn get_device_buffer_frame_size_range(
id: AudioDeviceID,
devtype: DeviceType,
) -> std::result::Result<(f64, f64), OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
let address = get_property_address(Property::DeviceBufferFrameSizeRange, devtype);
let mut size = mem::size_of::<AudioValueRange>();
let mut range = AudioValueRange::default();
let err = audio_object_get_property_data(id, &address, &mut size, &mut range);
if err == NO_ERR {
Ok((range.mMinimum, range.mMaximum))
} else {
Err(err)
}
}
enum Property {
DeviceBufferFrameSizeRange,
DeviceManufacturer,
DeviceName,
DeviceSource,
DeviceSourceName,
DeviceUID,
}
impl From<Property> for AudioObjectPropertySelector {
fn from(p: Property) -> Self {
match p {
Property::DeviceBufferFrameSizeRange => kAudioDevicePropertyBufferFrameSizeRange,
Property::DeviceManufacturer => kAudioObjectPropertyManufacturer,
Property::DeviceName => kAudioObjectPropertyName,
Property::DeviceSource => kAudioDevicePropertyDataSource,
Property::DeviceSourceName => kAudioDevicePropertyDataSourceNameForIDCFString,
Property::DeviceUID => kAudioDevicePropertyDeviceUID,
}
}
}
fn get_property_address(property: Property, devtype: DeviceType) -> AudioObjectPropertyAddress {
const GLOBAL: ffi::cubeb_device_type =
ffi::CUBEB_DEVICE_TYPE_INPUT | ffi::CUBEB_DEVICE_TYPE_OUTPUT;
let scope = match devtype.bits() {
ffi::CUBEB_DEVICE_TYPE_INPUT => kAudioDevicePropertyScopeInput,
ffi::CUBEB_DEVICE_TYPE_OUTPUT => kAudioDevicePropertyScopeOutput,
GLOBAL => kAudioObjectPropertyScopeGlobal,
_ => panic!("Invalid type"),
};
AudioObjectPropertyAddress {
mSelector: property.into(),
mScope: scope,
mElement: kAudioObjectPropertyElementMaster,
}
}

View File

@ -11,6 +11,7 @@ extern crate libc;
mod aggregate_device;
mod auto_array;
mod auto_release;
mod device_property;
mod mixer;
mod property_address;
mod resampler;
@ -26,6 +27,7 @@ use self::coreaudio_sys_utils::cf_mutable_dict::*;
use self::coreaudio_sys_utils::dispatch::*;
use self::coreaudio_sys_utils::string::*;
use self::coreaudio_sys_utils::sys::*;
use self::device_property::*;
use self::mixer::*;
use self::property_address::*;
use self::resampler::*;
@ -41,7 +43,7 @@ use std::cmp;
use std::ffi::{CStr, CString};
use std::fmt;
use std::mem;
use std::os::raw::{c_char, c_void};
use std::os::raw::c_void;
use std::ptr;
use std::slice;
use std::sync::atomic::{AtomicBool, AtomicI64, AtomicU32, AtomicU64, Ordering};
@ -317,7 +319,7 @@ fn create_auto_array(
desc: AudioStreamBasicDescription,
latency_frames: u32,
capacity: usize,
) -> Result<Box<AutoArrayWrapper>> {
) -> Result<Box<dyn AutoArrayWrapper>> {
assert_ne!(desc.mFormatFlags, 0);
assert_ne!(desc.mChannelsPerFrame, 0);
assert_ne!(latency_frames, 0);
@ -1168,22 +1170,6 @@ fn audiounit_set_channel_layout(
Ok(())
}
fn get_device_name(id: AudioDeviceID) -> CFStringRef {
let mut size = mem::size_of::<CFStringRef>();
let mut uiname: CFStringRef = ptr::null();
let address_uuid = AudioObjectPropertyAddress {
mSelector: kAudioDevicePropertyDeviceUID,
mScope: kAudioObjectPropertyScopeGlobal,
mElement: kAudioObjectPropertyElementMaster,
};
let err = audio_object_get_property_data(id, &address_uuid, &mut size, &mut uiname);
if err == NO_ERR {
uiname
} else {
ptr::null()
}
}
fn start_audiounit(unit: AudioUnit) -> Result<()> {
let status = audio_output_unit_start(unit);
if status == NO_ERR {
@ -1523,7 +1509,7 @@ fn convert_uint32_into_string(data: u32) -> CString {
CString::new(buffer).unwrap_or(empty)
}
fn audiounit_get_default_datasource(side: io_side) -> Result<(u32)> {
fn audiounit_get_default_datasource(side: io_side) -> Result<u32> {
let (devtype, address) = match side {
io_side::INPUT => (DeviceType::INPUT, INPUT_DATA_SOURCE_PROPERTY_ADDRESS),
io_side::OUTPUT => (DeviceType::OUTPUT, OUTPUT_DATA_SOURCE_PROPERTY_ADDRESS),
@ -1549,82 +1535,62 @@ fn audiounit_get_default_datasource_string(side: io_side) -> Result<CString> {
Ok(convert_uint32_into_string(data))
}
fn audiounit_strref_to_cstr_utf8(strref: CFStringRef) -> CString {
let empty = CString::default();
if strref.is_null() {
return empty;
}
let len = unsafe { CFStringGetLength(strref) };
// Add 1 to size to allow for '\0' termination character.
let size = unsafe { CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8) + 1 };
let mut buffer = vec![b'\x00'; size as usize];
let success = unsafe {
CFStringGetCString(
strref,
buffer.as_mut_ptr() as *mut c_char,
size,
kCFStringEncodingUTF8,
) != 0
};
if !success {
buffer.clear();
return empty;
}
// CString::new() will consume the input bytes vec and add a '\0' at the
// end of the bytes. We need to remove the '\0' from the bytes data
// returned from CFStringGetCString by ourselves to avoid memory leaks.
// The size returned from CFStringGetMaximumSizeForEncoding is always
// greater than or equal to the string length, where the string length
// is the number of characters from the beginning to nul-terminator('\0'),
// so we should shrink the string vector to fit that size.
let str_len = unsafe { libc::strlen(buffer.as_ptr() as *mut c_char) };
buffer.truncate(str_len); // Drop the elements from '\0'(including '\0').
CString::new(buffer).unwrap_or(empty)
}
fn audiounit_get_channel_count(devid: AudioObjectID, scope: AudioObjectPropertyScope) -> u32 {
let mut count: u32 = 0;
let mut size: usize = 0;
fn get_channel_count(devid: AudioObjectID, devtype: DeviceType) -> Result<u32> {
assert_ne!(devid, kAudioObjectUnknown);
let adr = AudioObjectPropertyAddress {
mSelector: kAudioDevicePropertyStreamConfiguration,
mScope: scope,
mScope: match devtype {
DeviceType::INPUT => kAudioDevicePropertyScopeInput,
DeviceType::OUTPUT => kAudioDevicePropertyScopeOutput,
_ => panic!("Invalid type"),
},
mElement: kAudioObjectPropertyElementMaster,
};
if audio_object_get_property_data_size(devid, &adr, &mut size) == NO_ERR && size > 0 {
let mut data: Vec<u8> = allocate_array_by_size(size);
let ptr = data.as_mut_ptr() as *mut AudioBufferList;
if audio_object_get_property_data(devid, &adr, &mut size, ptr) == NO_ERR {
let list: &AudioBufferList = unsafe { &(*ptr) };
let ptr = list.mBuffers.as_ptr() as *const AudioBuffer;
let len = list.mNumberBuffers as usize;
if len == 0 {
return 0;
}
let buffers = unsafe { slice::from_raw_parts(ptr, len) };
for buffer in buffers {
count += buffer.mNumberChannels;
}
}
let mut size: usize = 0;
let r = audio_object_get_property_data_size(devid, &adr, &mut size);
if r != NO_ERR {
return Err(Error::error());
}
count
assert_ne!(size, 0);
let mut data: Vec<u8> = allocate_array_by_size(size);
let ptr = data.as_mut_ptr() as *mut AudioBufferList;
let r = audio_object_get_property_data(devid, &adr, &mut size, ptr);
if r != NO_ERR {
return Err(Error::error());
}
let list = unsafe { &(*ptr) };
let ptr = list.mBuffers.as_ptr() as *const AudioBuffer;
let len = list.mNumberBuffers as usize;
let mut count = 0;
let buffers = unsafe { slice::from_raw_parts(ptr, len) };
for buffer in buffers {
count += buffer.mNumberChannels;
}
Ok(count)
}
fn audiounit_get_available_samplerate(
devid: AudioObjectID,
scope: AudioObjectPropertyScope,
devtype: DeviceType,
min: &mut u32,
max: &mut u32,
def: &mut u32,
) {
const GLOBAL: ffi::cubeb_device_type =
ffi::CUBEB_DEVICE_TYPE_INPUT | ffi::CUBEB_DEVICE_TYPE_OUTPUT;
let mut adr = AudioObjectPropertyAddress {
mSelector: 0,
mScope: scope,
mScope: match devtype.bits() {
ffi::CUBEB_DEVICE_TYPE_INPUT => kAudioDevicePropertyScopeInput,
ffi::CUBEB_DEVICE_TYPE_OUTPUT => kAudioDevicePropertyScopeOutput,
GLOBAL => kAudioObjectPropertyScopeGlobal,
_ => panic!("Invalid type"),
},
mElement: kAudioObjectPropertyElementMaster,
};
@ -1664,13 +1630,17 @@ fn audiounit_get_available_samplerate(
}
}
fn audiounit_get_device_presentation_latency(
devid: AudioObjectID,
scope: AudioObjectPropertyScope,
) -> u32 {
fn audiounit_get_device_presentation_latency(devid: AudioObjectID, devtype: DeviceType) -> u32 {
const GLOBAL: ffi::cubeb_device_type =
ffi::CUBEB_DEVICE_TYPE_INPUT | ffi::CUBEB_DEVICE_TYPE_OUTPUT;
let mut adr = AudioObjectPropertyAddress {
mSelector: 0,
mScope: scope,
mScope: match devtype.bits() {
ffi::CUBEB_DEVICE_TYPE_INPUT => kAudioDevicePropertyScopeInput,
ffi::CUBEB_DEVICE_TYPE_OUTPUT => kAudioDevicePropertyScopeOutput,
GLOBAL => kAudioObjectPropertyScopeGlobal,
_ => panic!("Invalid type"),
},
mElement: kAudioObjectPropertyElementMaster,
};
let mut size: usize = 0;
@ -1696,109 +1666,76 @@ fn audiounit_get_device_presentation_latency(
dev + stream
}
fn audiounit_create_device_from_hwdev(
dev_info: &mut ffi::cubeb_device_info,
fn create_cubeb_device_info(
devid: AudioObjectID,
devtype: DeviceType,
) -> Result<()> {
assert!(devtype == DeviceType::INPUT || devtype == DeviceType::OUTPUT);
let mut adr = AudioObjectPropertyAddress {
mSelector: 0,
mScope: 0,
mElement: kAudioObjectPropertyElementMaster,
};
let mut size: usize = 0;
adr.mScope = if devtype == DeviceType::OUTPUT {
kAudioDevicePropertyScopeOutput
} else {
kAudioDevicePropertyScopeInput
};
let ch = audiounit_get_channel_count(devid, adr.mScope);
if ch == 0 {
) -> Result<ffi::cubeb_device_info> {
let channels = get_channel_count(devid, devtype)?;
if channels == 0 {
// Invalid type for this device.
return Err(Error::error());
}
*dev_info = ffi::cubeb_device_info::default();
let mut dev_info = ffi::cubeb_device_info::default();
dev_info.max_channels = channels;
let mut device_id_str: CFStringRef = ptr::null();
size = mem::size_of::<CFStringRef>();
adr.mSelector = kAudioDevicePropertyDeviceUID;
let mut ret = audio_object_get_property_data(devid, &adr, &mut size, &mut device_id_str);
if ret == NO_ERR && !device_id_str.is_null() {
let c_string = audiounit_strref_to_cstr_utf8(device_id_str);
dev_info.device_id = c_string.into_raw();
assert!(
mem::size_of::<ffi::cubeb_devid>() >= mem::size_of_val(&devid),
"cubeb_devid can't represent devid"
);
dev_info.devid = devid as ffi::cubeb_devid;
assert!(
mem::size_of::<ffi::cubeb_devid>() >= mem::size_of_val(&devid),
"cubeb_devid can't represent devid"
);
dev_info.devid = devid as ffi::cubeb_devid;
dev_info.group_id = dev_info.device_id;
unsafe {
CFRelease(device_id_str as *const c_void);
match get_device_uid(devid, devtype) {
Ok(uid) => {
let c_string = uid.into_cstring();
dev_info.device_id = c_string.into_raw();
dev_info.group_id = dev_info.device_id;
}
Err(e) => {
cubeb_log!(
"Cannot get the uid for device {} in {:?} scope. Error: {}",
devid,
devtype,
e
);
}
}
let mut friendly_name_str: CFStringRef = ptr::null();
let mut ds: u32 = 0;
size = mem::size_of::<u32>();
adr.mSelector = kAudioDevicePropertyDataSource;
ret = audio_object_get_property_data(devid, &adr, &mut size, &mut ds);
if ret == NO_ERR {
let mut trl = AudioValueTranslation {
mInputData: &mut ds as *mut u32 as *mut c_void,
mInputDataSize: mem::size_of_val(&ds) as u32,
mOutputData: &mut friendly_name_str as *mut CFStringRef as *mut c_void,
mOutputDataSize: mem::size_of::<CFStringRef>() as u32,
};
adr.mSelector = kAudioDevicePropertyDataSourceNameForIDCFString;
size = mem::size_of::<AudioValueTranslation>();
audio_object_get_property_data(devid, &adr, &mut size, &mut trl);
}
// If there is no datasource for this device, fall back to the
// device name.
if friendly_name_str.is_null() {
size = mem::size_of::<CFStringRef>();
adr.mSelector = kAudioObjectPropertyName;
audio_object_get_property_data(devid, &adr, &mut size, &mut friendly_name_str);
}
if friendly_name_str.is_null() {
// Couldn't get a datasource name nor a device name, return a
// valid string of length 0.
let c_string = CString::default();
dev_info.friendly_name = c_string.into_raw();
} else {
let c_string = audiounit_strref_to_cstr_utf8(friendly_name_str);
dev_info.friendly_name = c_string.into_raw();
unsafe {
CFRelease(friendly_name_str as *const c_void);
let label = match get_device_label(devid, devtype) {
Ok(label) => label.into_cstring(),
Err(e) => {
cubeb_log!(
"Cannot get the label for device {} in {:?} scope. Error: {}",
devid,
devtype,
e
);
CString::default()
}
};
dev_info.friendly_name = label.into_raw();
let mut vendor_name_str: CFStringRef = ptr::null();
size = mem::size_of::<CFStringRef>();
adr.mSelector = kAudioObjectPropertyManufacturer;
ret = audio_object_get_property_data(devid, &adr, &mut size, &mut vendor_name_str);
if ret == NO_ERR && !vendor_name_str.is_null() {
let c_string = audiounit_strref_to_cstr_utf8(vendor_name_str);
dev_info.vendor_name = c_string.into_raw();
unsafe {
CFRelease(vendor_name_str as *const c_void);
match get_device_manufacturer(devid, devtype) {
Ok(vendor) => {
let vendor = vendor.into_cstring();
dev_info.vendor_name = vendor.into_raw();
}
Err(e) => {
cubeb_log!(
"Cannot get the manufacturer for device {} in {:?} scope. Error: {}",
devid,
devtype,
e
);
}
}
dev_info.device_type = if devtype == DeviceType::OUTPUT {
ffi::CUBEB_DEVICE_TYPE_OUTPUT
} else {
ffi::CUBEB_DEVICE_TYPE_INPUT
dev_info.device_type = match devtype {
DeviceType::INPUT => ffi::CUBEB_DEVICE_TYPE_INPUT,
DeviceType::OUTPUT => ffi::CUBEB_DEVICE_TYPE_OUTPUT,
_ => panic!("invalid type"),
};
dev_info.state = ffi::CUBEB_DEVICE_STATE_ENABLED;
dev_info.preferred = if devid == audiounit_get_default_device_id(devtype) {
ffi::CUBEB_DEVICE_PREF_ALL
@ -1806,31 +1743,32 @@ fn audiounit_create_device_from_hwdev(
ffi::CUBEB_DEVICE_PREF_NONE
};
dev_info.max_channels = ch;
dev_info.format = ffi::CUBEB_DEVICE_FMT_ALL;
dev_info.default_format = ffi::CUBEB_DEVICE_FMT_F32NE;
audiounit_get_available_samplerate(
devid,
adr.mScope,
devtype,
&mut dev_info.min_rate,
&mut dev_info.max_rate,
&mut dev_info.default_rate,
);
let latency = audiounit_get_device_presentation_latency(devid, adr.mScope);
let mut range = AudioValueRange::default();
adr.mSelector = kAudioDevicePropertyBufferFrameSizeRange;
size = mem::size_of::<AudioValueRange>();
ret = audio_object_get_property_data(devid, &adr, &mut size, &mut range);
if ret == NO_ERR {
dev_info.latency_lo = latency + range.mMinimum as u32;
dev_info.latency_hi = latency + range.mMaximum as u32;
} else {
dev_info.latency_lo = 10 * dev_info.default_rate / 1000; // Default to 10ms
dev_info.latency_hi = 100 * dev_info.default_rate / 1000; // Default to 10ms
}
let latency = audiounit_get_device_presentation_latency(devid, devtype);
Ok(())
let (latency_low, latency_high) = match get_device_buffer_frame_size_range(devid, devtype) {
Ok((min, max)) => (latency + min as u32, latency + max as u32),
Err(e) => {
cubeb_log!("Cannot get the buffer frame size for device {} in {:?} scope. Use default value instead. Error: {}", devid, devtype, e);
(
10 * dev_info.default_rate / 1000,
100 * dev_info.default_rate / 1000,
)
}
};
dev_info.latency_lo = latency_low;
dev_info.latency_hi = latency_high;
Ok(dev_info)
}
fn is_aggregate_device(device_info: &ffi::cubeb_device_info) -> bool {
@ -1900,16 +1838,12 @@ fn audiounit_get_devices_of_type(devtype: DeviceType) -> Vec<AudioObjectID> {
// Remove the aggregate device from the list of devices (if any).
devices.retain(|&device| {
let name = get_device_name(device);
if name.is_null() {
return true;
}
let private_device = cfstringref_from_static_string(PRIVATE_AGGREGATE_DEVICE_NAME);
unsafe {
let found = CFStringFind(name, private_device, 0).location;
CFRelease(private_device as *const c_void);
CFRelease(name as *const c_void);
found == kCFNotFound
if let Ok(uid) = get_device_global_uid(device) {
let uid = uid.into_string();
uid != PRIVATE_AGGREGATE_DEVICE_NAME
} else {
// Fail to get device uid.
true
}
});
@ -1919,14 +1853,9 @@ fn audiounit_get_devices_of_type(devtype: DeviceType) -> Vec<AudioObjectID> {
return devices;
}
let scope = if devtype == DeviceType::INPUT {
kAudioDevicePropertyScopeInput
} else {
kAudioDevicePropertyScopeOutput
};
let mut devices_in_scope = Vec::new();
for device in devices {
if audiounit_get_channel_count(device, scope) > 0 {
if get_channel_count(device, devtype).unwrap() > 0 {
devices_in_scope.push(device);
}
}
@ -2331,64 +2260,29 @@ impl ContextOps for AudioUnitContext {
devtype: DeviceType,
collection: &DeviceCollectionRef,
) -> Result<()> {
let input_devs = if devtype.contains(DeviceType::INPUT) {
audiounit_get_devices_of_type(DeviceType::INPUT)
} else {
Vec::<AudioObjectID>::new()
};
let output_devs = if devtype.contains(DeviceType::OUTPUT) {
audiounit_get_devices_of_type(DeviceType::OUTPUT)
} else {
Vec::<AudioObjectID>::new()
};
// Count number of input and output devices. This is not necessarily the same as
// the count of raw devices supported by the system since, for example, with Soundflower
// installed, some devices may report as being both input *and* output and cubeb
// separates those into two different devices.
let mut devices: Vec<ffi::cubeb_device_info> =
allocate_array(output_devs.len() + input_devs.len());
let mut count = 0;
if devtype.contains(DeviceType::OUTPUT) {
for dev in output_devs {
let device = &mut devices[count];
if audiounit_create_device_from_hwdev(device, dev, DeviceType::OUTPUT).is_err()
|| is_aggregate_device(device)
{
continue;
let mut device_infos = Vec::new();
let dev_types = [DeviceType::INPUT, DeviceType::OUTPUT];
for dev_type in dev_types.iter() {
if !devtype.contains(*dev_type) {
continue;
}
let devices = audiounit_get_devices_of_type(*dev_type);
for device in devices {
if let Ok(info) = create_cubeb_device_info(device, *dev_type) {
if !is_aggregate_device(&info) {
device_infos.push(info);
}
}
count += 1;
}
}
if devtype.contains(DeviceType::INPUT) {
for dev in input_devs {
let device = &mut devices[count];
if audiounit_create_device_from_hwdev(device, dev, DeviceType::INPUT).is_err()
|| is_aggregate_device(device)
{
continue;
}
count += 1;
}
}
// Remove the redundant space, set len to count.
devices.truncate(count);
let (ptr, len) = if device_infos.is_empty() {
(ptr::null_mut(), 0)
} else {
forget_vec(device_infos)
};
let coll = unsafe { &mut *collection.as_ptr() };
if count > 0 {
let (ptr, len) = forget_vec(devices);
coll.device = ptr;
coll.count = len;
} else {
coll.device = ptr::null_mut();
coll.count = 0;
}
coll.device = ptr;
coll.count = len;
Ok(())
}
fn device_collection_destroy(&mut self, collection: &mut DeviceCollectionRef) -> Result<()> {
@ -2556,7 +2450,7 @@ struct CoreStreamData<'ctx> {
device_layout: ChannelLayout,
// Hold the input samples in every input callback iteration.
// Only accessed on input/output callback thread and during initial configure.
input_linear_buffer: Option<Box<AutoArrayWrapper>>,
input_linear_buffer: Option<Box<dyn AutoArrayWrapper>>,
// Listeners indicating what system events are monitored.
default_input_listener: Option<device_property_listener>,
default_output_listener: Option<device_property_listener>,
@ -3066,7 +2960,7 @@ impl<'ctx> CoreStreamData<'ctx> {
stream.current_latency_frames.store(
audiounit_get_device_presentation_latency(
self.output_device.id,
kAudioDevicePropertyScopeOutput,
DeviceType::OUTPUT,
),
Ordering::SeqCst,
);

View File

@ -62,16 +62,8 @@ namespace recordreplay {
(const PLDHashTableOps* aFirstOps, \
const PLDHashTableOps* aSecondOps), \
(aFirstOps, aSecondOps)) \
Macro(SetWeakPointerJSRoot, \
(const void* aPtr, JSObject* aJSObj), (aPtr, aJSObj)) \
Macro(RegisterTrigger, \
(void* aObj, const std::function<void()>& aCallback), \
(aObj, \
aCallback)) Macro(UnregisterTrigger, (void* aObj), \
(aObj)) Macro(ActivateTrigger, \
(void* aObj), (aObj)) \
Macro(ExecuteTriggers, (), ()) Macro( \
InternalRecordReplayAssert, \
Macro(InternalHoldJSObject, (JSObject* aJSObj), (aJSObj)) \
Macro(InternalRecordReplayAssert, \
(const char* aFormat, va_list aArgs), \
(aFormat, \
aArgs)) Macro(InternalRecordReplayAssertBytes, \

View File

@ -187,54 +187,11 @@ static inline void DestroyPLDHashTableCallbacks(const PLDHashTableOps* aOps);
static inline void MovePLDHashTableContents(const PLDHashTableOps* aFirstOps,
const PLDHashTableOps* aSecondOps);
// Associate an arbitrary pointer with a JS object root while replaying. This
// is useful for replaying the behavior of weak pointers.
MFBT_API void SetWeakPointerJSRoot(const void* aPtr, JSObject* aJSObj);
// API for ensuring that a function executes at a consistent point when
// recording or replaying. This is primarily needed for finalizers and other
// activity during a GC that can perform recorded events (because GCs can
// occur at different times and behave differently between recording and
// replay, thread events are disallowed during a GC). Triggers can be
// registered at a point where thread events are allowed, then activated at
// a point where thread events are not allowed. When recording, the trigger's
// callback will execute at the next point when ExecuteTriggers is called on
// the thread which originally registered the trigger (typically at the top of
// the thread's event loop), and when replaying the callback will execute at
// the same point, even if it was never activated.
//
// Below is an example of how this API can be used.
//
// // This structure's lifetime is managed by the GC.
// struct GarbageCollectedHolder {
// GarbageCollectedHolder() {
// RegisterTrigger(this, [=]() { this->DestroyContents(); });
// }
// ~GarbageCollectedHolder() {
// UnregisterTrigger(this);
// }
//
// void Finalize() {
// // During finalization, thread events are disallowed.
// if (IsRecordingOrReplaying()) {
// ActivateTrigger(this);
// } else {
// DestroyContents();
// }
// }
//
// // This is free to release resources held by the system, communicate with
// // other threads or processes, and so forth. When replaying, this may
// // be called before the GC has actually collected this object, but since
// // the GC will have already collected this object at this point in the
// // recording, this object will never be accessed again.
// void DestroyContents();
// };
MFBT_API void RegisterTrigger(void* aObj,
const std::function<void()>& aCallback);
MFBT_API void UnregisterTrigger(void* aObj);
MFBT_API void ActivateTrigger(void* aObj);
MFBT_API void ExecuteTriggers();
// Prevent a JS object from ever being collected while recording or replaying.
// GC behavior is non-deterministic when recording/replaying, and preventing
// an object from being collected ensures that finalizers which might interact
// with the recording will not execute.
static inline void HoldJSObject(JSObject* aJSObj);
// Some devtools operations which execute in a replaying process can cause code
// to run which did not run while recording. For example, the JS debugger can
@ -419,15 +376,8 @@ MOZ_MAKE_RECORD_REPLAY_WRAPPER_VOID(MovePLDHashTableContents,
(aFirstOps, aSecondOps))
MOZ_MAKE_RECORD_REPLAY_WRAPPER_VOID(InvalidateRecording, (const char* aWhy),
(aWhy))
MOZ_MAKE_RECORD_REPLAY_WRAPPER_VOID(
RegisterWeakPointer,
(const void* aPtr, const std::function<void(bool)>& aCallback),
(aPtr, aCallback))
MOZ_MAKE_RECORD_REPLAY_WRAPPER_VOID(UnregisterWeakPointer, (const void* aPtr),
(aPtr))
MOZ_MAKE_RECORD_REPLAY_WRAPPER_VOID(WeakPointerAccess,
(const void* aPtr, bool aSuccess),
(aPtr, aSuccess))
MOZ_MAKE_RECORD_REPLAY_WRAPPER_VOID(HoldJSObject, (JSObject* aObject),
(aObject))
MOZ_MAKE_RECORD_REPLAY_WRAPPER_VOID(RecordReplayAssertBytes,
(const void* aData, size_t aSize),
(aData, aSize))

View File

@ -27,9 +27,17 @@ public class TelemetryActivationPingDelegate extends BrowserAppDelegate {
private TelemetryDispatcher telemetryDispatcher; // lazy
// We don't upload in onCreate because that's only called when the Activity needs to be instantiated
// and it's possible the system will never free the Activity from memory.
//
// We don't upload in onResume/onPause because that will be called each time the Activity is obscured,
// including by our own Activities/dialogs, and there is no reason to upload each time we're unobscured.
//
// We're left with onStart/onStop and we upload in onStart because onStop is not guaranteed to be called
// and we want to upload the first run ASAP (e.g. to get install data before the app may crash).
@Override
public void onCreate(BrowserApp browserApp, Bundle savedInstanceState) {
super.onCreate(browserApp, savedInstanceState);
public void onStart(BrowserApp browserApp) {
super.onStart(browserApp);
uploadActivationPing(browserApp);
}

View File

@ -4880,6 +4880,17 @@
value: @IS_NIGHTLY_BUILD@
mirror: always
#---------------------------------------------------------------------------
# Prefs starting with "mathml."
#---------------------------------------------------------------------------
# Whether to disable legacy names "thin", "thick" and "medium" for the
# linethickness attribute of the mfrac element.
- name: mathml.mfrac_linethickness_names.disabled
type: bool
value: @IS_NIGHTLY_BUILD@
mirror: always
#---------------------------------------------------------------------------
# Prefs starting with "media."
#---------------------------------------------------------------------------

View File

@ -54,6 +54,7 @@ pref_groups = [
'keyword',
'layers',
'layout',
'mathml',
'media',
'mousewheel',
'network',

View File

@ -36,7 +36,6 @@ from mozbuild.frontend.data import (
IPDLCollection,
LocalizedPreprocessedFiles,
LocalizedFiles,
RustLibrary,
SharedLibrary,
StaticLibrary,
UnifiedSources,
@ -252,7 +251,7 @@ class CommonBackend(BuildBackend):
def expand(lib, recurse_objs, system_libs):
if isinstance(lib, (HostLibrary, StaticLibrary)):
if not isinstance(lib, HostLibrary) and lib.no_expand_lib:
if lib.no_expand_lib:
static_libs.append(lib)
recurse_objs = False
elif recurse_objs:
@ -276,9 +275,7 @@ class CommonBackend(BuildBackend):
system_libs = not isinstance(input_bin, (HostLibrary, StaticLibrary))
for lib in input_bin.linked_libraries:
if isinstance(lib, RustLibrary):
continue
elif isinstance(lib, (HostLibrary, StaticLibrary)):
if isinstance(lib, (HostLibrary, StaticLibrary)):
expand(lib, True, system_libs)
elif isinstance(lib, SharedLibrary):
if lib not in seen_libs:

View File

@ -31,6 +31,7 @@ from .common import CommonBackend
from ..frontend.data import (
BaseLibrary,
BaseProgram,
BaseRustLibrary,
ChromeManifestEntry,
ComputedFlags,
ConfigFileSubstitution,
@ -59,9 +60,7 @@ from ..frontend.data import (
ObjdirPreprocessedFiles,
PerSourceFlag,
Program,
RustLibrary,
HostSharedLibrary,
HostRustLibrary,
RustProgram,
RustTests,
SharedLibrary,
@ -479,6 +478,8 @@ class RecursiveMakeBackend(CommonBackend):
f = mozpath.relpath(f, base)
for var in variables:
backend_file.write('%s += %s\n' % (var, f))
self._compile_graph[mozpath.join(
backend_file.relobjdir, 'target-objects')]
elif isinstance(obj, (HostSources, HostGeneratedSources)):
suffix_map = {
'.c': 'HOST_CSRCS',
@ -495,6 +496,8 @@ class RecursiveMakeBackend(CommonBackend):
f = mozpath.relpath(f, base)
for var in variables:
backend_file.write('%s += %s\n' % (var, f))
self._compile_graph[mozpath.join(
backend_file.relobjdir, 'host-objects')]
elif isinstance(obj, VariablePassthru):
# Sorted so output is consistent and we don't bump mtimes.
for k, v in sorted(obj.variables.items()):
@ -678,7 +681,7 @@ class RecursiveMakeBackend(CommonBackend):
elif isinstance(obj, InstallationTarget):
self._process_installation_target(obj, backend_file)
elif isinstance(obj, RustLibrary):
elif isinstance(obj, BaseRustLibrary):
self.backend_input_files.add(obj.cargo_file)
self._process_rust_library(obj, backend_file)
# No need to call _process_linked_libraries, because Rust
@ -840,38 +843,19 @@ class RecursiveMakeBackend(CommonBackend):
# rest of the compile graph.
target_name = mozpath.basename(root)
if target_name not in ('target', 'target-shared', 'host'):
if target_name not in ('target', 'target-objects',
'host', 'host-objects'):
non_default_roots[target_name].append(root)
non_default_graphs[target_name][root] = self._compile_graph[root]
del self._compile_graph[root]
targets_per_directory = defaultdict(list)
for target in self._compile_graph.iterkeys():
targets_per_directory[mozpath.dirname(target)].append(
mozpath.basename(target))
# In directories that have both a shared and a static library, there
# may also be source files that are applied to both. What can happen
# then is that both the shared and static library are attempted to be
# built in parallel via other dependencies, and both try to build the
# same source files at the same time, and that can lead to race
# conditions and build failures. This means we need an implicit
# dependency between the shared and the static library that the library
# graph doesn't necessarily know about, so we encode it in the compile
# graph manually.
for directory, targets in targets_per_directory.iteritems():
if 'target-shared' in targets and 'target' in targets:
self._compile_graph[mozpath.join(directory, 'target-shared')].add(
mozpath.join(directory, 'target'))
for root in chain(*non_default_roots.values()):
compile_roots.remove(root)
dirname = mozpath.dirname(root)
# If a directory only contains non-default compile targets, we don't
# attempt to dump symbols there.
if (dirname in self._no_skip['syms'] and
'%s/target' % dirname not in self._compile_graph and
'%s/target-shared' % dirname not in self._compile_graph):
'%s/target' % dirname not in self._compile_graph):
self._no_skip['syms'].remove(dirname)
add_category_rules('compile', compile_roots, self._compile_graph)
@ -1088,6 +1072,9 @@ class RecursiveMakeBackend(CommonBackend):
backend_file.write('%s += %s\n' % (
non_unified_var, ' '.join(source_files)))
self._compile_graph[mozpath.join(
backend_file.relobjdir, 'target-objects')]
def _process_directory_traversal(self, obj, backend_file):
"""Process a data.DirectoryTraversal instance."""
fh = backend_file.fh
@ -1389,9 +1376,6 @@ class RecursiveMakeBackend(CommonBackend):
def _build_target_for_obj(self, obj):
if hasattr(obj, 'output_category') and obj.output_category:
target_name = obj.output_category
elif isinstance(obj, SharedLibrary):
assert obj.KIND == 'target'
target_name = 'target-shared'
else:
target_name = obj.KIND
return '%s/%s' % (mozpath.relpath(obj.objdir,
@ -1402,10 +1386,6 @@ class RecursiveMakeBackend(CommonBackend):
return os.path.normpath(mozpath.join(mozpath.relpath(lib.objdir, obj.objdir),
name))
# This will create the node even if there aren't any linked libraries.
build_target = self._build_target_for_obj(obj)
self._compile_graph[build_target]
objs, no_pgo_objs, shared_libs, os_libs, static_libs = self._expand_libs(obj)
obj_target = obj.name
@ -1475,54 +1455,51 @@ class RecursiveMakeBackend(CommonBackend):
write_obj_deps(obj_target, objs_ref, pgo_objs_ref)
for lib in shared_libs:
assert obj.KIND != 'host'
backend_file.write_once('SHARED_LIBS += %s\n' %
pretty_relpath(lib, lib.import_name))
for lib in static_libs:
backend_file.write_once('STATIC_LIBS += %s\n' %
pretty_relpath(lib, lib.import_name))
# We have to link any Rust libraries after all intermediate static
# libraries have been listed to ensure that the Rust libraries are
# searched after the C/C++ objects that might reference Rust symbols.
var = 'HOST_LIBS' if obj.KIND == 'host' else 'STATIC_LIBS'
for lib in chain(
(l for l in static_libs if not isinstance(l, BaseRustLibrary)),
(l for l in static_libs if isinstance(l, BaseRustLibrary)),
):
backend_file.write_once('%s += %s\n' %
(var, pretty_relpath(lib, lib.import_name)))
for lib in os_libs:
if obj.KIND == 'target':
backend_file.write_once('OS_LIBS += %s\n' % lib)
else:
backend_file.write_once('HOST_EXTRA_LIBS += %s\n' % lib)
for lib in obj.linked_libraries:
if not isinstance(lib, ExternalLibrary):
self._compile_graph[build_target].add(
self._build_target_for_obj(lib))
if isinstance(lib, HostRustLibrary):
backend_file.write_once('HOST_LIBS += %s\n' %
pretty_relpath(lib, lib.import_name))
if not isinstance(obj, (StaticLibrary, HostLibrary)) or obj.no_expand_lib:
# This will create the node even if there aren't any linked libraries.
build_target = self._build_target_for_obj(obj)
self._compile_graph[build_target]
# We have to link any Rust libraries after all intermediate static
# libraries have been listed to ensure that the Rust libraries are
# searched after the C/C++ objects that might reference Rust symbols.
if isinstance(obj, (SharedLibrary, Program)):
self._process_rust_libraries(obj, backend_file, pretty_relpath)
# Make the build target depend on all the target/host-objects that
# recursively are linked into it.
def recurse_libraries(obj):
for lib in obj.linked_libraries:
if isinstance(lib, (StaticLibrary, HostLibrary)) and not lib.no_expand_lib:
recurse_libraries(lib)
elif not isinstance(lib, ExternalLibrary):
self._compile_graph[build_target].add(
self._build_target_for_obj(lib))
relobjdir = mozpath.relpath(obj.objdir, self.environment.topobjdir)
objects_target = mozpath.join(relobjdir, '%s-objects' % obj.KIND)
if objects_target in self._compile_graph:
self._compile_graph[build_target].add(objects_target)
recurse_libraries(obj)
# Process library-based defines
self._process_defines(obj.lib_defines, backend_file)
def _process_rust_libraries(self, obj, backend_file, pretty_relpath):
assert isinstance(obj, (SharedLibrary, Program))
# If this library does not depend on any Rust libraries, then we are done.
direct_linked = [l for l in obj.linked_libraries if isinstance(l, RustLibrary)]
if not direct_linked:
return
# We should have already checked this in Linkable.link_library.
assert len(direct_linked) == 1
# TODO: see bug 1310063 for checking dependencies are set up correctly.
direct_linked = direct_linked[0]
backend_file.write('RUST_STATIC_LIB := %s\n' %
pretty_relpath(direct_linked, direct_linked.import_name))
for lib in direct_linked.linked_system_libs:
backend_file.write_once('OS_LIBS += %s\n' % lib)
def _process_final_target_files(self, obj, files, backend_file):
target = obj.install_target
path = mozpath.basedir(target, (

View File

@ -395,10 +395,6 @@ class LinkageWrongKindError(Exception):
"""Error thrown when trying to link objects of the wrong kind"""
class LinkageMultipleRustLibrariesError(Exception):
"""Error thrown when trying to link multiple Rust libraries to an object"""
class Linkable(ContextDerived):
"""Generic context derived container object for programs and libraries"""
__slots__ = (
@ -425,13 +421,6 @@ class Linkable(ContextDerived):
assert isinstance(obj, BaseLibrary)
if obj.KIND != self.KIND:
raise LinkageWrongKindError('%s != %s' % (obj.KIND, self.KIND))
# Linking multiple Rust libraries into an object would result in
# multiple copies of the Rust standard library, as well as linking
# errors from duplicate symbols.
if isinstance(obj, RustLibrary) and any(isinstance(l, RustLibrary)
for l in self.linked_libraries):
raise LinkageMultipleRustLibrariesError("Cannot link multiple Rust libraries into %s"
% self)
self.linked_libraries.append(obj)
if obj.cxx_link and not isinstance(obj, SharedLibrary):
self.cxx_link = True
@ -681,9 +670,8 @@ class StaticLibrary(Library):
self.no_expand_lib = no_expand_lib
class RustLibrary(StaticLibrary):
"""Context derived container object for a static library"""
__slots__ = (
class BaseRustLibrary(object):
slots = (
'cargo_file',
'crate_type',
'dependencies',
@ -692,13 +680,9 @@ class RustLibrary(StaticLibrary):
'target_dir',
'output_category',
)
TARGET_SUBST_VAR = 'RUST_TARGET'
FEATURES_VAR = 'RUST_LIBRARY_FEATURES'
LIB_FILE_VAR = 'RUST_LIBRARY_FILE'
def __init__(self, context, basename, cargo_file, crate_type, dependencies,
features, target_dir, **args):
StaticLibrary.__init__(self, context, basename, **args)
def init(self, context, basename, cargo_file, crate_type, dependencies,
features, target_dir):
self.cargo_file = cargo_file
self.crate_type = crate_type
# We need to adjust our naming here because cargo replaces '-' in
@ -726,6 +710,24 @@ class RustLibrary(StaticLibrary):
self.deps_path = mozpath.join(build_dir, 'deps')
class RustLibrary(StaticLibrary, BaseRustLibrary):
"""Context derived container object for a rust static library"""
KIND = 'target'
TARGET_SUBST_VAR = 'RUST_TARGET'
FEATURES_VAR = 'RUST_LIBRARY_FEATURES'
LIB_FILE_VAR = 'RUST_LIBRARY_FILE'
__slots__ = BaseRustLibrary.slots
def __init__(self, context, basename, cargo_file, crate_type, dependencies,
features, target_dir, link_into=None):
StaticLibrary.__init__(self, context, basename, link_into=link_into,
# A rust library is a real static library ; make
# it known to the build system.
no_expand_lib=True)
BaseRustLibrary.init(self, context, basename, cargo_file,
crate_type, dependencies, features, target_dir)
class SharedLibrary(Library):
"""Context derived container object for a shared library"""
__slots__ = (
@ -839,14 +841,23 @@ class ExternalSharedLibrary(SharedLibrary, ExternalLibrary):
class HostLibrary(HostMixin, BaseLibrary):
"""Context derived container object for a host library"""
KIND = 'host'
no_expand_lib = False
class HostRustLibrary(HostMixin, RustLibrary):
class HostRustLibrary(HostLibrary, BaseRustLibrary):
"""Context derived container object for a host rust library"""
KIND = 'host'
TARGET_SUBST_VAR = 'RUST_HOST_TARGET'
FEATURES_VAR = 'HOST_RUST_LIBRARY_FEATURES'
LIB_FILE_VAR = 'HOST_RUST_LIBRARY_FILE'
__slots__ = BaseRustLibrary.slots
no_expand_lib = True
def __init__(self, context, basename, cargo_file, crate_type, dependencies,
features, target_dir):
HostLibrary.__init__(self, context, basename)
BaseRustLibrary.init(self, context, basename, cargo_file,
crate_type, dependencies, features, target_dir)
class TestManifest(ContextDerived):

View File

@ -289,6 +289,31 @@ class TreeMetadataEmitter(LoggingMixin):
'\n '.join(shared_libs), lib.basename),
contexts[lib.objdir])
@memoize
def rust_libraries(obj):
libs = []
for o in obj.linked_libraries:
if isinstance(o, (HostRustLibrary, RustLibrary)):
libs.append(o)
elif isinstance(o, (HostLibrary, StaticLibrary)):
libs.extend(rust_libraries(o))
return libs
def check_rust_libraries(obj):
rust_libs = set(rust_libraries(obj))
if len(rust_libs) <= 1:
return
if isinstance(obj, (Library, HostLibrary)):
what = '"%s" library' % obj.basename
else:
what = '"%s" program' % obj.name
raise SandboxValidationError(
'Cannot link the following Rust libraries into the %s:\n'
'%s\nOnly one is allowed.'
% (what, '\n'.join(' - %s' % r.basename
for r in sorted(rust_libs))),
contexts[obj.objdir])
# Propagate LIBRARY_DEFINES to all child libraries recursively.
def propagate_defines(outerlib, defines):
outerlib.lib_defines.update(defines)
@ -302,6 +327,7 @@ class TreeMetadataEmitter(LoggingMixin):
for lib in (l for libs in self._libs.values() for l in libs):
if isinstance(lib, Library):
propagate_defines(lib, lib.lib_defines)
check_rust_libraries(lib)
yield lib
for lib in (l for libs in self._libs.values() for l in libs):
@ -321,6 +347,8 @@ class TreeMetadataEmitter(LoggingMixin):
yield flags_obj
for obj in self._binaries.values():
if isinstance(obj, Linkable):
check_rust_libraries(obj)
yield obj
LIBRARY_NAME_VAR = {

View File

@ -169,7 +169,9 @@ def process_gyp_result(gyp_result, gyp_dir_attrs, path, config, output,
for t in s.get('dependencies', []) + s.get('dependencies_original', []):
ty = targets[t]['type']
if ty in ('static_library', 'shared_library'):
use_libs.append(targets[t]['target_name'])
l = targets[t]['target_name']
if l not in use_libs:
use_libs.append(l)
# Manually expand out transitive dependencies--
# gyp won't do this for static libs or none targets.
if ty in ('static_library', 'none'):
@ -184,12 +186,17 @@ def process_gyp_result(gyp_result, gyp_dir_attrs, path, config, output,
os_libs = []
for l in libs:
if l.startswith('-'):
os_libs.append(l)
if l not in os_libs:
os_libs.append(l)
elif l.endswith('.lib'):
os_libs.append(l[:-4])
l = l[:-4]
if l not in os_libs:
os_libs.append(l)
elif l:
# For library names passed in from moz.build.
use_libs.append(os.path.basename(l))
l = os.path.basename(l)
if l not in use_libs:
use_libs.append(l)
if spec['type'] == 'none':
if not ('actions' in spec or 'copies' in spec):

View File

@ -28,7 +28,6 @@ from mozbuild.frontend.data import (
HostSources,
IPDLCollection,
JARManifest,
LinkageMultipleRustLibrariesError,
LocalInclude,
LocalizedFiles,
LocalizedPreprocessedFiles,
@ -1519,8 +1518,9 @@ class TestEmitterBasic(unittest.TestCase):
'''Test that linking multiple Rust libraries throws an error'''
reader = self.reader('multiple-rust-libraries',
extra_substs=dict(RUST_TARGET='i686-pc-windows-msvc'))
with self.assertRaisesRegexp(LinkageMultipleRustLibrariesError,
'Cannot link multiple Rust libraries'):
with self.assertRaisesRegexp(
SandboxValidationError,
'Cannot link the following Rust libraries'):
self.read_topsrcdir(reader)
def test_rust_library_features(self):

View File

@ -26,6 +26,8 @@
#include "pk11sdr.h" // For PK11SDR_Encrypt, PK11SDR_Decrypt
#include "ssl.h" // For SSL_ClearSessionCache
static mozilla::LazyLogModule gSDRLog("sdrlog");
using namespace mozilla;
using dom::Promise;
@ -73,8 +75,22 @@ void BackgroundSdrDecryptStrings(const nsTArray<nsCString>& encryptedStrings,
nsCString plainText;
rv = sdrService->DecryptString(encryptedString, plainText);
if (NS_WARN_IF(NS_FAILED(rv))) {
break;
if (NS_FAILED(rv)) {
if (rv == NS_ERROR_NOT_AVAILABLE) {
// Master Password entry was canceled. Don't keep prompting again.
break;
}
// NS_ERROR_ILLEGAL_VALUE or NS_ERROR_FAILURE could be due to bad data for
// a single string but we still want to decrypt the others.
// Callers of `decryptMany` in crypto-SDR.js assume there will be an
// equal number of usernames and passwords so use an empty string to keep
// this assumption true.
MOZ_LOG(gSDRLog, LogLevel::Warning,
("Couldn't decrypt string: %s", encryptedString.get()));
plainTexts.AppendElement(nullptr);
rv = NS_OK;
continue;
}
plainTexts.AppendElement(NS_ConvertUTF8toUTF16(plainText));

View File

@ -21,6 +21,32 @@ const gTokenPasswordDialogs = {
QueryInterface: ChromeUtils.generateQI([Ci.nsITokenPasswordDialogs]),
};
let gMockPrompter = {
promptPassword(dialogTitle, text, password, checkMsg, checkValue) {
// Returning false simulates the user canceling the password prompt.
return false;
},
QueryInterface: ChromeUtils.generateQI([Ci.nsIPrompt]),
};
// Mock nsIWindowWatcher. PSM calls getNewPrompter on this to get an nsIPrompt
// to call promptPassword. We return the mock one, above.
let gWindowWatcher = {
getNewPrompter: () => gMockPrompter,
QueryInterface: ChromeUtils.generateQI([Ci.nsIWindowWatcher]),
};
add_task(function setup() {
let windowWatcherCID = MockRegistrar.register(
"@mozilla.org/embedcomp/window-watcher;1",
gWindowWatcher
);
registerCleanupFunction(() => {
MockRegistrar.unregister(windowWatcherCID);
});
});
add_task(function testEncryptString() {
let sdr = Cc["@mozilla.org/security/sdr;1"].getService(
Ci.nsISecretDecoderRing
@ -187,3 +213,60 @@ add_task(async function testAsyncDecryptStrings() {
);
}
});
add_task(async function testAsyncDecryptInvalidStrings() {
let sdr = Cc["@mozilla.org/security/sdr;1"].getService(
Ci.nsISecretDecoderRing
);
// Test invalid inputs for sdr.asyncDecryptStrings
let testCases = [
"~bmV0cGxheQ==", // invalid base64 encoding
"bmV0cGxheQ==", // valid base64 characters but not encrypted
"https://www.example.com", // website address from erroneous migration
];
let decrypteds = await sdr.asyncDecryptStrings(testCases);
equal(
decrypteds.length,
testCases.length,
"each testcase should still return a response"
);
for (let i = 0; i < decrypteds.length; i++) {
let decrypted = decrypteds[i];
equal(
decrypted,
"",
"decrypted string should be empty when trying to decrypt an invalid input with asyncDecryptStrings"
);
Assert.throws(
() => sdr.decryptString(testCases[i]),
/NS_ERROR_ILLEGAL_VALUE|NS_ERROR_FAILURE/,
`Check testcase would have thrown: ${testCases[i]}`
);
}
});
add_task(async function testAsyncDecryptLoggedOut() {
// Set a master password.
let token = Cc["@mozilla.org/security/pk11tokendb;1"]
.getService(Ci.nsIPK11TokenDB)
.getInternalKeyToken();
token.initPassword("password");
token.logoutSimple();
let sdr = Cc["@mozilla.org/security/sdr;1"].getService(
Ci.nsISecretDecoderRing
);
await Assert.rejects(
sdr.asyncDecryptStrings(["irrelevant"]),
/NS_ERROR_NOT_AVAILABLE/,
"Check error is thrown instead of returning empty strings"
);
token.reset();
token.initPassword("");
});

View File

@ -1,24 +0,0 @@
<!doctype html>
<script src="util.js"></script>
<body>
<script>
const styles = `:host { background: red; width: 100px; height: 100px; display: block; }`.repeat(10000);
customElements.define("custom-element", class CustomElement extends HTMLElement {
connectedCallback() {
this.attachShadow({ mode: "open" });
const style = document.createElement("style");
style.textContent = styles;
this.shadowRoot.appendChild(style);
}
});
perf_start();
for (let i = 0; i < 1000; ++i)
document.body.appendChild(document.createElement("custom-element"));
onload = function() {
flush_layout(document.body);
perf_finish();
};
</script>

View File

@ -1,26 +0,0 @@
<!doctype html>
<script src="util.js"></script>
<body>
<script>
const styles = `:host { background: red; width: 100px; height: 100px; display: block; }`.repeat(10000);
const blob = URL.createObjectURL(new Blob([styles], { type: 'text/css' }));
customElements.define("custom-element", class CustomElement extends HTMLElement {
connectedCallback() {
this.attachShadow({ mode: "open" });
const link = document.createElement("link");
link.rel = "stylesheet";
link.href = blob;
this.shadowRoot.appendChild(link);
}
});
perf_start();
for (let i = 0; i < 1000; ++i)
document.body.appendChild(document.createElement("custom-element"));
onload = function() {
flush_layout(document.body);
perf_finish();
};
</script>

View File

@ -23,5 +23,3 @@
% http://localhost/tests/perf-reftest-singletons/id-getter-7.html
% http://localhost/tests/perf-reftest-singletons/abspos-reflow-1.html
% http://localhost/tests/perf-reftest-singletons/scrollbar-styles-1.html
% http://localhost/tests/perf-reftest-singletons/inline-style-cache-1.html
% http://localhost/tests/perf-reftest-singletons/link-style-cache-1.html

View File

@ -0,0 +1,2 @@
[text-decoration-skip-ink-sidewayslr-001.html]
prefs: [layout.css.text-decoration-skip-ink.enabled:true]

View File

@ -0,0 +1,3 @@
[text-decoration-skip-ink-sidewayslr-002.html]
prefs: [layout.css.text-decoration-skip-ink.enabled:true,
layout.css.text-underline-offset.enabled:true]

View File

@ -0,0 +1,2 @@
[text-decoration-skip-ink-sidewaysrl-001.html]
prefs: [layout.css.text-decoration-skip-ink.enabled:true]

View File

@ -0,0 +1,3 @@
[text-decoration-skip-ink-sidewaysrl-002.html]
prefs: [layout.css.text-decoration-skip-ink.enabled:true,
layout.css.text-underline-offset.enabled:true]

View File

@ -0,0 +1,6 @@
[text-decoration-skip-ink-upright-001.html]
prefs: [layout.css.text-decoration-skip-ink.enabled:true,
layout.css.text-underline-offset.enabled:true]
[reference/text-decoration-skip-ink-upright-001-notref.html]
expected: fail
bug: 1572294

View File

@ -0,0 +1,7 @@
[text-decoration-skip-ink-upright-002.html]
prefs: [layout.css.text-decoration-skip-ink.enabled:true,
layout.css.text-underline-offset.enabled:true]
[reference/text-decoration-skip-ink-002-ref.html]
expected: FAIL
bug: 1572294

View File

@ -0,0 +1,3 @@
[text-decoration-skip-ink-vertical-001.html]
prefs: [layout.css.text-decoration-skip-ink.enabled:true,
layout.css.text-underline-offset.enabled:true]

View File

@ -0,0 +1,3 @@
[text-decoration-skip-ink-vertical-002.html]
prefs: [layout.css.text-decoration-skip-ink.enabled:true,
layout.css.text-underline-offset.enabled:true]

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