зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-central to mozilla-inbound. r=merge a=merge
This commit is contained in:
Коммит
02a34cdd40
|
@ -177,7 +177,7 @@
|
|||
|
||||
<html:a class="help-button" target="_blank" aria-label="&helpButton2.label;">&helpButton2.label;</html:a>
|
||||
|
||||
<vbox class="main-content" flex="1">
|
||||
<vbox class="main-content" flex="1" align="start">
|
||||
<vbox class="pane-container">
|
||||
<hbox class="search-container" pack="end">
|
||||
<textbox type="search" id="searchInput" hidden="true" clickSelectsAll="true"/>
|
||||
|
|
|
@ -54,7 +54,7 @@ uninstaller::
|
|||
$(RM) -r $(CONFIG_DIR)
|
||||
$(MKDIR) $(CONFIG_DIR)
|
||||
$(INSTALL) $(addprefix $(srcdir)/,$(INSTALLER_FILES)) $(CONFIG_DIR)
|
||||
$(INSTALL) $(addprefix $(DIST)/branding/,$(BRANDING_FILES)) $(CONFIG_DIR)
|
||||
$(INSTALL) $(addprefix $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/,$(BRANDING_FILES)) $(CONFIG_DIR)
|
||||
$(call py_action,preprocessor,-Fsubstitution $(DEFINES) $(ACDEFINES) \
|
||||
$(srcdir)/nsis/defines.nsi.in -o $(CONFIG_DIR)/defines.nsi)
|
||||
$(PYTHON) $(topsrcdir)/toolkit/mozapps/installer/windows/nsis/preprocess-locale.py \
|
||||
|
@ -76,7 +76,7 @@ $(CONFIG_DIR)/setup.exe::
|
|||
$(RM) -r $(CONFIG_DIR)
|
||||
$(MKDIR) $(CONFIG_DIR)
|
||||
$(INSTALL) $(addprefix $(srcdir)/,$(INSTALLER_FILES)) $(CONFIG_DIR)
|
||||
$(INSTALL) $(addprefix $(DIST)/branding/,$(BRANDING_FILES)) $(CONFIG_DIR)
|
||||
$(INSTALL) $(addprefix $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/,$(BRANDING_FILES)) $(CONFIG_DIR)
|
||||
$(call py_action,preprocessor,-Fsubstitution $(DEFINES) $(ACDEFINES) \
|
||||
$(srcdir)/nsis/defines.nsi.in -o $(CONFIG_DIR)/defines.nsi)
|
||||
$(PYTHON) $(topsrcdir)/toolkit/mozapps/installer/windows/nsis/preprocess-locale.py \
|
||||
|
|
|
@ -19,8 +19,6 @@ PWD := $(CURDIR)
|
|||
# These are defaulted to be compatible with the files the wget-en-US target
|
||||
# pulls. You may override them if you provide your own files.
|
||||
ZIP_IN ?= $(ABS_DIST)/$(PACKAGE)
|
||||
WIN32_INSTALLER_IN ?= $(ABS_DIST)/$(PKG_INST_PATH)$(PKG_INST_BASENAME).exe
|
||||
RETRIEVE_WINDOWS_INSTALLER = 1
|
||||
|
||||
MOZ_LANGPACK_EID=langpack-$(AB_CD)@firefox.mozilla.org
|
||||
# For Nightly, we know where to get the builds from to do local repacks
|
||||
|
@ -43,21 +41,6 @@ endif
|
|||
MOZ_SFX_PACKAGE=$(topsrcdir)/other-licenses/7zstub/firefox/7zSD.sfx
|
||||
MOZ_INSTALLER_PATH=$(topsrcdir)/browser/installer/windows
|
||||
|
||||
ifeq (WINNT,$(OS_ARCH))
|
||||
UNINSTALLER_PACKAGE_HOOK = $(RM) -r $(STAGEDIST)/uninstall; \
|
||||
$(NSINSTALL) -D $(STAGEDIST)/uninstall; \
|
||||
cp ../installer/windows/l10ngen/helper.exe $(STAGEDIST)/uninstall; \
|
||||
$(RM) $(ABS_DIST)/l10n-stage/setup.exe; \
|
||||
cp ../installer/windows/l10ngen/setup.exe $(ABS_DIST)/l10n-stage; \
|
||||
$(NULL)
|
||||
|
||||
STUB_HOOK = $(NSINSTALL) -D '$(ABS_DIST)/$(PKG_INST_PATH)'; \
|
||||
$(RM) '$(ABS_DIST)/$(PKG_INST_PATH)$(PKG_STUB_BASENAME).exe'; \
|
||||
cp ../installer/windows/l10ngen/stub.exe '$(ABS_DIST)/$(PKG_INST_PATH)$(PKG_STUB_BASENAME).exe'; \
|
||||
chmod 0755 '$(ABS_DIST)/$(PKG_INST_PATH)$(PKG_STUB_BASENAME).exe'; \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
SEARCHPLUGINS_FILENAMES := $(shell $(call py_action,output_searchplugins_list,$(srcdir)/search/list.json $(AB_CD)))
|
||||
SEARCHPLUGINS_PATH := .deps/generated_$(AB_CD)
|
||||
SEARCHPLUGINS_TARGET := libs searchplugins
|
||||
|
@ -135,26 +118,25 @@ ifdef NIGHTLY_BUILD
|
|||
@$(MAKE) -C ../extensions/webcompat-reporter/locales chrome AB_CD=$*
|
||||
endif
|
||||
|
||||
repackage-win32-installer: WIN32_INSTALLER_OUT=$(ABS_DIST)/$(PKG_INST_PATH)$(PKG_INST_BASENAME).exe
|
||||
repackage-win32-installer: $(call ESCAPE_WILDCARD,$(WIN32_INSTALLER_IN)) $(SUBMAKEFILES) libs-$(AB_CD)
|
||||
@echo 'Repackaging $(WIN32_INSTALLER_IN) into $(WIN32_INSTALLER_OUT).'
|
||||
$(MAKE) -C $(DEPTH)/$(MOZ_BRANDING_DIRECTORY) export
|
||||
package-win32-installer: WIN32_INSTALLER_OUT=$(ABS_DIST)/$(PKG_INST_PATH)$(PKG_INST_BASENAME).exe
|
||||
package-win32-installer: MOZ_PKG_FORMAT=SFX7Z
|
||||
package-win32-installer: $(SUBMAKEFILES)
|
||||
@echo 'Packaging $(WIN32_INSTALLER_OUT).'
|
||||
$(MAKE) -C ../installer/windows CONFIG_DIR=l10ngen l10ngen/setup.exe l10ngen/7zSD.sfx
|
||||
$(MAKE) repackage-zip \
|
||||
AB_CD=$(AB_CD) \
|
||||
MOZ_PKG_FORMAT=SFX7Z \
|
||||
ZIP_IN='$(WIN32_INSTALLER_IN)' \
|
||||
ZIP_OUT='$(WIN32_INSTALLER_OUT)' \
|
||||
SFX_HEADER='$(PWD)/../installer/windows/l10ngen/7zSD.sfx \
|
||||
$(topsrcdir)/browser/installer/windows/app.tag'
|
||||
|
||||
ifeq (WINNT,$(OS_ARCH))
|
||||
repackage-win32-installer-%: unpack
|
||||
@$(MAKE) repackage-win32-installer AB_CD=$* WIN32_INSTALLER_IN='$(WIN32_INSTALLER_IN)'
|
||||
|
||||
repackage-zip-%: repackage-win32-installer-%
|
||||
else
|
||||
repackage-win32-installer-%: ;
|
||||
$(RM) -r $(STAGEDIST)/uninstall
|
||||
$(NSINSTALL) -D $(STAGEDIST)/uninstall
|
||||
cp ../installer/windows/l10ngen/helper.exe $(STAGEDIST)/uninstall
|
||||
$(RM) $(ABS_DIST)/l10n-stage/setup.exe
|
||||
cp ../installer/windows/l10ngen/setup.exe $(ABS_DIST)/l10n-stage
|
||||
$(NSINSTALL) -D '$(ABS_DIST)/$(PKG_INST_PATH)'
|
||||
(cd $(DIST)/l10n-stage; \
|
||||
$(MAKE_PACKAGE))
|
||||
mv -f '$(DIST)/l10n-stage/$(PACKAGE)' '$(WIN32_INSTALLER_OUT)'
|
||||
if test -f '$(DIST)/l10n-stage/$(PACKAGE).asc'; then mv -f '$(DIST)/l10n-stage/$(PACKAGE).asc' '$(WIN32_INSTALLER_OUT).asc'; fi
|
||||
ifdef MOZ_STUB_INSTALLER
|
||||
$(RM) '$(ABS_DIST)/$(PKG_INST_PATH)$(PKG_STUB_BASENAME).exe'
|
||||
cp ../installer/windows/l10ngen/stub.exe '$(ABS_DIST)/$(PKG_INST_PATH)$(PKG_STUB_BASENAME).exe'
|
||||
chmod 0755 '$(ABS_DIST)/$(PKG_INST_PATH)$(PKG_STUB_BASENAME).exe'
|
||||
endif
|
||||
|
||||
|
||||
|
@ -165,7 +147,14 @@ langpack: langpack-$(AB_CD)
|
|||
# tinderbox scripts. Alter it with caution.
|
||||
|
||||
installers-%: IS_LANGUAGE_REPACK=1
|
||||
installers-%: clobber-% langpack-% repackage-win32-installer-% repackage-zip-%
|
||||
installers-%:
|
||||
@$(MAKE) clobber-$*
|
||||
@$(MAKE) libs-$*
|
||||
@$(MAKE) package-langpack-$*
|
||||
@$(MAKE) repackage-zip-$*
|
||||
ifeq (WINNT,$(OS_ARCH))
|
||||
@$(MAKE) package-win32-installer AB_CD=$*
|
||||
endif
|
||||
@echo 'repackaging done'
|
||||
|
||||
ifdef MOZ_UPDATER
|
||||
|
@ -212,6 +201,6 @@ l10n-check::
|
|||
@# not being reset, overwriting the value they would get with MOZ_SIMPLE_PACKAGE_NAME
|
||||
@# reset.
|
||||
$(MAKE) installers-x-test L10NBASEDIR='$(PWD)' \
|
||||
ZIP_IN='$(ZIP_IN)' WIN32_INSTALLER_IN='$(WIN32_INSTALLER_IN)' MOZ_SIMPLE_PACKAGE_NAME=
|
||||
ZIP_IN='$(ZIP_IN)' MOZ_SIMPLE_PACKAGE_NAME=
|
||||
$(PYTHON) $(topsrcdir)/toolkit/mozapps/installer/unpack.py $(DIST)/l10n-stage/$(MOZ_PKG_DIR)$(_RESPATH)
|
||||
cd $(DIST)/l10n-stage && test $$(cat $(MOZ_PKG_DIR)$(_RESPATH)/update.locale) = x-test
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
}
|
||||
|
||||
.pane-container {
|
||||
/* A workaround to keep the container always float on the `top: 0` (Bug 1377009) */
|
||||
display: block;
|
||||
max-width: 800px;
|
||||
width: 664px;
|
||||
min-width: 530px;
|
||||
}
|
||||
|
||||
#mainPrefPane {
|
||||
|
@ -629,25 +631,25 @@ separator.thin:not([orient="vertical"]) {
|
|||
background-image: url("chrome://global/skin/icons/help.svg");
|
||||
-moz-context-properties: fill, fill-opacity;
|
||||
fill: currentColor;
|
||||
fill-opacity: 0.8;
|
||||
font-size: 13px;
|
||||
line-height: 16px;
|
||||
height: 16px;
|
||||
background-position: 8px;
|
||||
line-height: 36px;
|
||||
height: 36px;
|
||||
width: 168px;
|
||||
background-position: left 10px top 10px;
|
||||
background-size: 16px;
|
||||
padding-inline-start: 38px;
|
||||
margin-inline-start: 44px;
|
||||
margin-inline-start: 34px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.help-button:-moz-locale-dir(rtl) {
|
||||
background-position: right 8px top 0;
|
||||
background-position: right 10px top 10px;
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.help-button:hover {
|
||||
fill: currentColor;
|
||||
fill-opacity: 0.9;
|
||||
}
|
||||
|
||||
.help-button:link,
|
||||
|
|
|
@ -1207,6 +1207,31 @@ KeyframeEffectReadOnly::GetKeyframes(JSContext*& aCx,
|
|||
}
|
||||
|
||||
bool isServo = mDocument->IsStyledByServo();
|
||||
bool isCSSAnimation = mAnimation && mAnimation->AsCSSAnimation();
|
||||
|
||||
// For Servo, when we have CSS Animation @keyframes with variables, we convert
|
||||
// shorthands to longhands if needed, and store a reference to the unparsed
|
||||
// value. When it comes time to serialize, however, what do you serialize for
|
||||
// a longhand that comes from a variable reference in a shorthand? Servo says,
|
||||
// "an empty string" which is not particularly helpful.
|
||||
//
|
||||
// We should just store shorthands as-is (bug 1391537) and then return the
|
||||
// variable references, but for now, since we don't do that, and in order to
|
||||
// be consistent with Gecko, we just expand the variables (assuming we have
|
||||
// enough context to do so). For that we need to grab the style context so we
|
||||
// know what custom property values to provide.
|
||||
RefPtr<nsStyleContext> styleContext;
|
||||
if (isServo && isCSSAnimation) {
|
||||
// The following will flush style but that's ok since if you update
|
||||
// a variable's computed value, you expect to see that updated value in the
|
||||
// result of getKeyframes().
|
||||
//
|
||||
// If we don't have a target, the following will return null. In that case
|
||||
// we might end up returning variables as-is or empty string. That should be
|
||||
// acceptable however, since such a case is rare and this is only
|
||||
// short-term (and unshipped) behavior until bug 1391537 is fixed.
|
||||
styleContext = GetTargetStyleContext();
|
||||
}
|
||||
|
||||
for (const Keyframe& keyframe : mKeyframes) {
|
||||
// Set up a dictionary object for the explicit members
|
||||
|
@ -1237,9 +1262,13 @@ KeyframeEffectReadOnly::GetKeyframes(JSContext*& aCx,
|
|||
nsAutoString stringValue;
|
||||
if (isServo) {
|
||||
if (propertyValue.mServoDeclarationBlock) {
|
||||
const ServoStyleContext* servoStyleContext =
|
||||
styleContext ? styleContext->AsServo() : nullptr;
|
||||
Servo_DeclarationBlock_SerializeOneValue(
|
||||
propertyValue.mServoDeclarationBlock,
|
||||
propertyValue.mProperty, &stringValue);
|
||||
propertyValue.mProperty,
|
||||
&stringValue,
|
||||
servoStyleContext);
|
||||
} else {
|
||||
RawServoAnimationValue* value =
|
||||
mBaseStyleValuesForServo.GetWeak(propertyValue.mProperty);
|
||||
|
|
|
@ -28,9 +28,6 @@
|
|||
#include "mozilla/layers/APZCCallbackHelper.h"
|
||||
#include "ClientLayerManager.h"
|
||||
#include "nsQueryObject.h"
|
||||
#ifdef MOZ_FMP4
|
||||
#include "MP4Decoder.h"
|
||||
#endif
|
||||
#include "CubebUtils.h"
|
||||
|
||||
#include "nsIScrollableFrame.h"
|
||||
|
@ -2474,35 +2471,6 @@ nsDOMWindowUtils::GetUsingAdvancedLayers(bool* retval)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::GetSupportsHardwareH264Decoding(JS::MutableHandle<JS::Value> aPromise)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
|
||||
NS_ENSURE_STATE(window);
|
||||
nsCOMPtr<nsIGlobalObject> parentObject =
|
||||
do_QueryInterface(window->GetCurrentInnerWindow());
|
||||
NS_ENSURE_STATE(parentObject);
|
||||
#ifdef MOZ_FMP4
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
NS_ENSURE_STATE(widget);
|
||||
LayerManager *mgr = widget->GetLayerManager();
|
||||
NS_ENSURE_STATE(mgr);
|
||||
RefPtr<Promise> promise =
|
||||
MP4Decoder::IsVideoAccelerated(mgr->AsKnowsCompositor(), parentObject);
|
||||
NS_ENSURE_STATE(promise);
|
||||
aPromise.setObject(*promise->PromiseObj());
|
||||
#else
|
||||
ErrorResult rv;
|
||||
RefPtr<Promise> promise = Promise::Create(parentObject, rv);
|
||||
if (rv.Failed()) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
promise->MaybeResolve(NS_LITERAL_STRING("No; Compiled without MP4 support."));
|
||||
aPromise.setObject(*promise->PromiseObj());
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::GetCurrentAudioBackend(nsAString& aBackend)
|
||||
{
|
||||
|
|
|
@ -29,11 +29,13 @@ function test() {
|
|||
var newTab = BrowserTestUtils.addTab(gBrowser);
|
||||
gBrowser.selectedTab = newTab;
|
||||
gTestBrowser = gBrowser.selectedBrowser;
|
||||
newTab.linkedBrowser.stop()
|
||||
|
||||
BrowserTestUtils.browserLoaded(gTestBrowser, true /*includeSubFrames*/).then(MixedTest1A);
|
||||
var url = gHttpTestRoot + "file_bug902350.html";
|
||||
gTestBrowser.loadURI(url);
|
||||
BrowserTestUtils.browserLoaded(gTestBrowser).then(() => {
|
||||
// about:blank is expected to be loaded here.
|
||||
var url = gHttpTestRoot + "file_bug902350.html";
|
||||
BrowserTestUtils.browserLoaded(gTestBrowser, true /*includeSubFrames*/).then(MixedTest1A);
|
||||
gTestBrowser.loadURI(url);
|
||||
});
|
||||
}
|
||||
|
||||
// Need to capture 2 loads, one for the main page and one for the iframe
|
||||
|
|
|
@ -5846,6 +5846,12 @@ HTMLMediaElement::UpdateReadyStateInternal()
|
|||
return;
|
||||
}
|
||||
|
||||
if (!mPaused || mAutoplaying) {
|
||||
// We only want to reset mWaitingForKey if we have played all decoded data
|
||||
// or if we haven't played anything yet.
|
||||
mWaitingForKey = NOT_WAITING_FOR_KEY;
|
||||
}
|
||||
|
||||
// Now see if we should set HAVE_ENOUGH_DATA.
|
||||
// If it's something we don't know the size of, then we can't
|
||||
// make a real estimate, so we go straight to HAVE_ENOUGH_DATA once
|
||||
|
@ -5854,7 +5860,7 @@ HTMLMediaElement::UpdateReadyStateInternal()
|
|||
// autoplay elements for live streams will never play. Otherwise we
|
||||
// move to HAVE_ENOUGH_DATA if we can play through the entire media
|
||||
// without stopping to buffer.
|
||||
if (mWaitingForKey == NOT_WAITING_FOR_KEY && mDecoder->CanPlayThrough()) {
|
||||
if (mDecoder->CanPlayThrough()) {
|
||||
LOG(LogLevel::Debug, ("MediaElement %p UpdateReadyStateInternal() "
|
||||
"Decoder can play through", this));
|
||||
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
|
||||
|
@ -5919,7 +5925,6 @@ void HTMLMediaElement::ChangeReadyState(nsMediaReadyState aState)
|
|||
mReadyState >= nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA) {
|
||||
DispatchAsyncEvent(NS_LITERAL_STRING("canplay"));
|
||||
if (!mPaused) {
|
||||
mWaitingForKey = NOT_WAITING_FOR_KEY;
|
||||
NotifyAboutPlaying();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1420,14 +1420,6 @@ interface nsIDOMWindowUtils : nsISupports {
|
|||
*/
|
||||
readonly attribute boolean usingAdvancedLayers;
|
||||
|
||||
/**
|
||||
* Returns a Promise that will be resolved with a string once the capabilities
|
||||
* of the h264 decoder have been determined.
|
||||
* Success does not mean that all h264 video decoding will be done
|
||||
* in hardware.
|
||||
*/
|
||||
readonly attribute jsval supportsHardwareH264Decoding;
|
||||
|
||||
/**
|
||||
* Returns the current audio backend as a free-form string.
|
||||
*/
|
||||
|
|
|
@ -6,12 +6,9 @@
|
|||
|
||||
#include "MP4Decoder.h"
|
||||
#include "MediaContainerType.h"
|
||||
#include "MediaFormatReader.h"
|
||||
#include "MP4Demuxer.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "mozilla/SharedThreadPool.h"
|
||||
#include "VideoUtils.h"
|
||||
|
||||
#include "PDMFactory.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -164,108 +161,4 @@ MP4Decoder::IsEnabled()
|
|||
return MediaPrefs::MP4Enabled();
|
||||
}
|
||||
|
||||
// sTestH264ExtraData represents the content of the avcC atom found in
|
||||
// an AVC1 h264 video. It contains the H264 SPS and PPS NAL.
|
||||
// the structure of the avcC atom is as follow:
|
||||
// write(0x1); // version, always 1
|
||||
// write(sps[0].data[1]); // profile
|
||||
// write(sps[0].data[2]); // compatibility
|
||||
// write(sps[0].data[3]); // level
|
||||
// write(0xFC | 3); // reserved (6 bits), NULA length size - 1 (2 bits)
|
||||
// write(0xE0 | 1); // reserved (3 bits), num of SPS (5 bits)
|
||||
// write_word(sps[0].size); // 2 bytes for length of SPS
|
||||
// for(size_t i=0 ; i < sps[0].size ; ++i)
|
||||
// write(sps[0].data[i]); // data of SPS
|
||||
// write(&b, pps.size()); // num of PPS
|
||||
// for(size_t i=0 ; i < pps.size() ; ++i) {
|
||||
// write_word(pps[i].size); // 2 bytes for length of PPS
|
||||
// for(size_t j=0 ; j < pps[i].size ; ++j)
|
||||
// write(pps[i].data[j]); // data of PPS
|
||||
// }
|
||||
// }
|
||||
// here we have a h264 Baseline, 640x360
|
||||
// We use a 640x360 extradata, as some video framework (Apple VT) will never
|
||||
// attempt to use hardware decoding for small videos.
|
||||
static const uint8_t sTestH264ExtraData[] = {
|
||||
0x01, 0x42, 0xc0, 0x1e, 0xff, 0xe1, 0x00, 0x17, 0x67, 0x42,
|
||||
0xc0, 0x1e, 0xbb, 0x40, 0x50, 0x17, 0xfc, 0xb8, 0x08, 0x80,
|
||||
0x00, 0x00, 0x32, 0x00, 0x00, 0x0b, 0xb5, 0x07, 0x8b, 0x17,
|
||||
0x50, 0x01, 0x00, 0x04, 0x68, 0xce, 0x32, 0xc8
|
||||
};
|
||||
|
||||
static already_AddRefed<MediaDataDecoder>
|
||||
CreateTestH264Decoder(layers::KnowsCompositor* aKnowsCompositor,
|
||||
VideoInfo& aConfig,
|
||||
TaskQueue* aTaskQueue)
|
||||
{
|
||||
aConfig.mMimeType = "video/avc";
|
||||
aConfig.mId = 1;
|
||||
aConfig.mDuration = media::TimeUnit::FromMicroseconds(40000);
|
||||
aConfig.mImage = aConfig.mDisplay = nsIntSize(640, 360);
|
||||
aConfig.mExtraData = new MediaByteBuffer();
|
||||
aConfig.mExtraData->AppendElements(sTestH264ExtraData,
|
||||
MOZ_ARRAY_LENGTH(sTestH264ExtraData));
|
||||
|
||||
RefPtr<PDMFactory> platform = new PDMFactory();
|
||||
RefPtr<MediaDataDecoder> decoder(platform->CreateDecoder({ aConfig, aTaskQueue, aKnowsCompositor }));
|
||||
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<dom::Promise>
|
||||
MP4Decoder::IsVideoAccelerated(layers::KnowsCompositor* aKnowsCompositor, nsIGlobalObject* aParent)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
ErrorResult rv;
|
||||
RefPtr<dom::Promise> promise;
|
||||
promise = dom::Promise::Create(aParent, rv);
|
||||
if (rv.Failed()) {
|
||||
rv.SuppressException();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<TaskQueue> taskQueue = new TaskQueue(
|
||||
GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
|
||||
"MP4Decoder::IsVideoAccelerated::taskQueue");
|
||||
VideoInfo config;
|
||||
RefPtr<MediaDataDecoder> decoder(CreateTestH264Decoder(aKnowsCompositor, config, taskQueue));
|
||||
if (!decoder) {
|
||||
taskQueue->BeginShutdown();
|
||||
taskQueue->AwaitShutdownAndIdle();
|
||||
promise->MaybeResolve(NS_LITERAL_STRING("No; Failed to create H264 decoder"));
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
decoder->Init()
|
||||
->Then(aParent->AbstractMainThreadFor(TaskCategory::Other),
|
||||
__func__,
|
||||
[promise, decoder, taskQueue] (TrackInfo::TrackType aTrack) {
|
||||
nsCString failureReason;
|
||||
bool ok = decoder->IsHardwareAccelerated(failureReason);
|
||||
nsAutoString result;
|
||||
if (ok) {
|
||||
result.AssignLiteral("Yes");
|
||||
} else {
|
||||
result.AssignLiteral("No");
|
||||
}
|
||||
if (failureReason.Length()) {
|
||||
result.AppendLiteral("; ");
|
||||
AppendUTF8toUTF16(failureReason, result);
|
||||
}
|
||||
decoder->Shutdown();
|
||||
taskQueue->BeginShutdown();
|
||||
taskQueue->AwaitShutdownAndIdle();
|
||||
promise->MaybeResolve(result);
|
||||
},
|
||||
[promise, decoder, taskQueue] (MediaResult aError) {
|
||||
decoder->Shutdown();
|
||||
taskQueue->BeginShutdown();
|
||||
taskQueue->AwaitShutdownAndIdle();
|
||||
promise->MaybeResolve(NS_LITERAL_STRING("No; Failed to initialize H264 decoder"));
|
||||
});
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
#define MP4Decoder_h_
|
||||
|
||||
class nsACString;
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/layers/KnowsCompositor.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -41,9 +39,6 @@ public:
|
|||
// Returns true if the MP4 backend is preffed on.
|
||||
static bool IsEnabled();
|
||||
|
||||
static already_AddRefed<dom::Promise>
|
||||
IsVideoAccelerated(layers::KnowsCompositor* aKnowsCompositor, nsIGlobalObject* aParent);
|
||||
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -378,17 +378,21 @@ GetFirefoxAppPath(nsCOMPtr<nsIFile> aPluginContainerPath,
|
|||
}
|
||||
|
||||
static bool
|
||||
GetPluginContainerSigPath(nsCOMPtr<nsIFile> aPluginContainerPath,
|
||||
nsCOMPtr<nsIFile>& aOutPluginContainerSigPath)
|
||||
GetSigPath(const int aRelativeLayers,
|
||||
const nsString& aTargetSigFileName,
|
||||
nsCOMPtr<nsIFile> aExecutablePath,
|
||||
nsCOMPtr<nsIFile>& aOutSigPath)
|
||||
{
|
||||
// The sig file will be located in
|
||||
// xxxx/NightlyDebug.app/Contents/Resources/XUL.sig
|
||||
// xxxx/NightlyDebug.app/Contents/Resources/firefox.sig
|
||||
// xxxx/NightlyDebug.app/Contents/MacOS/plugin-container.app/Contents/Resources/plugin-container.sig
|
||||
// On MacOS the plugin-container.sig file is a few parent directories up from
|
||||
// plugin-container.
|
||||
// Start to search the path from the path of plugin-container.
|
||||
MOZ_ASSERT(aPluginContainerPath);
|
||||
nsCOMPtr<nsIFile> path = aPluginContainerPath;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
// On MacOS the sig file is a few parent directories up from
|
||||
// its executable file.
|
||||
// Start to search the path from the path of the executable file we provided.
|
||||
MOZ_ASSERT(aExecutablePath);
|
||||
nsCOMPtr<nsIFile> path = aExecutablePath;
|
||||
for (int i = 0; i < aRelativeLayers; i++) {
|
||||
nsCOMPtr<nsIFile> parent;
|
||||
if (NS_FAILED(path->GetParent(getter_AddRefs(parent)))) {
|
||||
return false;
|
||||
|
@ -396,9 +400,9 @@ GetPluginContainerSigPath(nsCOMPtr<nsIFile> aPluginContainerPath,
|
|||
path = parent;
|
||||
}
|
||||
MOZ_ASSERT(path);
|
||||
aOutPluginContainerSigPath = path;
|
||||
aOutSigPath = path;
|
||||
return NS_SUCCEEDED(path->Append(NS_LITERAL_STRING("Resources"))) &&
|
||||
NS_SUCCEEDED(path->Append(NS_LITERAL_STRING("plugin-container.sig")));
|
||||
NS_SUCCEEDED(path->Append(aTargetSigFileName));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -433,7 +437,7 @@ GMPChild::MakeCDMHostVerificationPaths()
|
|||
nsCString sigFilePath;
|
||||
#if defined(XP_MACOSX)
|
||||
nsCOMPtr<nsIFile> sigFile;
|
||||
if (GetPluginContainerSigPath(path, sigFile) &&
|
||||
if (GetSigPath(2, NS_LITERAL_STRING("plugin-container.sig"), path, sigFile) &&
|
||||
NS_SUCCEEDED(sigFile->GetPath(str))) {
|
||||
sigFilePath = NS_ConvertUTF16toUTF8(str);
|
||||
} else {
|
||||
|
@ -464,9 +468,21 @@ GMPChild::MakeCDMHostVerificationPaths()
|
|||
NS_SUCCEEDED(appDir->Clone(getter_AddRefs(path))) &&
|
||||
NS_SUCCEEDED(path->Append(FIREFOX_FILE)) && FileExists(path) &&
|
||||
ResolveLinks(path) && NS_SUCCEEDED(path->GetPath(str))) {
|
||||
nsCString filePath = NS_ConvertUTF16toUTF8(str);
|
||||
nsCString sigFilePath;
|
||||
nsCOMPtr<nsIFile> sigFile;
|
||||
if (GetSigPath(2, NS_LITERAL_STRING("firefox.sig"), path, sigFile) &&
|
||||
NS_SUCCEEDED(sigFile->GetPath(str))) {
|
||||
sigFilePath = NS_ConvertUTF16toUTF8(str);
|
||||
} else {
|
||||
// Cannot successfully get the sig file path.
|
||||
// Assume it is located at the same place as firefox alternatively.
|
||||
sigFilePath = nsCString(NS_ConvertUTF16toUTF8(str) +
|
||||
NS_LITERAL_CSTRING(".sig"));
|
||||
}
|
||||
paths.AppendElement(
|
||||
MakePair(nsCString(NS_ConvertUTF16toUTF8(str)),
|
||||
nsCString(NS_ConvertUTF16toUTF8(str) + NS_LITERAL_CSTRING(".sig"))));
|
||||
MakePair(Move(filePath),
|
||||
Move(sigFilePath)));
|
||||
}
|
||||
#else
|
||||
// Note: re-using 'path' var here, as on Windows/Linux we assume Firefox
|
||||
|
@ -486,9 +502,26 @@ GMPChild::MakeCDMHostVerificationPaths()
|
|||
if (NS_SUCCEEDED(appDir->Clone(getter_AddRefs(path))) &&
|
||||
NS_SUCCEEDED(path->Append(XUL_LIB_FILE)) && FileExists(path) &&
|
||||
ResolveLinks(path) && NS_SUCCEEDED(path->GetPath(str))) {
|
||||
nsCString filePath = NS_ConvertUTF16toUTF8(str);
|
||||
nsCString sigFilePath;
|
||||
#if defined(XP_MACOSX)
|
||||
nsCOMPtr<nsIFile> sigFile;
|
||||
if (GetSigPath(2, NS_LITERAL_STRING("XUL.sig"), path, sigFile) &&
|
||||
NS_SUCCEEDED(sigFile->GetPath(str))) {
|
||||
sigFilePath = NS_ConvertUTF16toUTF8(str);
|
||||
} else {
|
||||
// Cannot successfully get the sig file path.
|
||||
// Assume it is located at the same place as XUL alternatively.
|
||||
sigFilePath = nsCString(NS_ConvertUTF16toUTF8(str) +
|
||||
NS_LITERAL_CSTRING(".sig"));
|
||||
}
|
||||
#else
|
||||
sigFilePath = nsCString(NS_ConvertUTF16toUTF8(str) +
|
||||
NS_LITERAL_CSTRING(".sig"));
|
||||
#endif
|
||||
paths.AppendElement(
|
||||
MakePair(nsCString(NS_ConvertUTF16toUTF8(str)),
|
||||
nsCString(NS_ConvertUTF16toUTF8(str) + NS_LITERAL_CSTRING(".sig"))));
|
||||
MakePair(Move(filePath),
|
||||
Move(sigFilePath)));
|
||||
}
|
||||
|
||||
return paths;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "nsPrintfCString.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "mozilla/mscom/EnsureMTA.h"
|
||||
|
||||
const CLSID CLSID_VideoProcessorMFT =
|
||||
{
|
||||
|
@ -648,6 +649,7 @@ private:
|
|||
uint32_t mWidth = 0;
|
||||
uint32_t mHeight = 0;
|
||||
UINT mDeviceManagerToken = 0;
|
||||
bool mConfiuredForSize = false;
|
||||
};
|
||||
|
||||
bool
|
||||
|
@ -778,22 +780,35 @@ D3D11DXVA2Manager::InitInternal(layers::KnowsCompositor* aKnowsCompositor,
|
|||
return hr;
|
||||
}
|
||||
|
||||
mTransform = new MFTDecoder();
|
||||
hr = mTransform->Create(CLSID_VideoProcessorMFT);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
aFailureReason = nsPrintfCString(
|
||||
"MFTDecoder::Create(CLSID_VideoProcessorMFT) failed with code %X", hr);
|
||||
return hr;
|
||||
}
|
||||
// The IMFTransform interface used by MFTDecoder is documented to require to
|
||||
// run on an MTA thread.
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ee892371(v=vs.85).aspx#components
|
||||
// The main thread (where this function is called) is STA, not MTA.
|
||||
RefPtr<MFTDecoder> mft;
|
||||
mozilla::mscom::EnsureMTA([&]() -> void {
|
||||
mft = new MFTDecoder();
|
||||
hr = mft->Create(CLSID_VideoProcessorMFT);
|
||||
|
||||
if (!SUCCEEDED(hr)) {
|
||||
aFailureReason = nsPrintfCString(
|
||||
"MFTDecoder::Create(CLSID_VideoProcessorMFT) failed with code %X", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
hr = mft->SendMFTMessage(MFT_MESSAGE_SET_D3D_MANAGER,
|
||||
ULONG_PTR(mDXGIDeviceManager.get()));
|
||||
if (!SUCCEEDED(hr)) {
|
||||
aFailureReason = nsPrintfCString("MFTDecoder::SendMFTMessage(MFT_MESSAGE_"
|
||||
"SET_D3D_MANAGER) failed with code %X",
|
||||
hr);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
hr = mTransform->SendMFTMessage(MFT_MESSAGE_SET_D3D_MANAGER,
|
||||
ULONG_PTR(mDXGIDeviceManager.get()));
|
||||
if (!SUCCEEDED(hr)) {
|
||||
aFailureReason = nsPrintfCString("MFTDecoder::SendMFTMessage(MFT_MESSAGE_"
|
||||
"SET_D3D_MANAGER) failed with code %X",
|
||||
hr);
|
||||
return hr;
|
||||
}
|
||||
mTransform = mft;
|
||||
|
||||
RefPtr<ID3D11VideoDevice> videoDevice;
|
||||
hr = mDevice->QueryInterface(
|
||||
|
@ -947,14 +962,18 @@ D3D11DXVA2Manager::CopyToImage(IMFSample* aVideoSample,
|
|||
} else {
|
||||
// Our video sample is in NV12 format but our output texture is in BGRA.
|
||||
// Use MFT to do color conversion.
|
||||
hr = mTransform->Input(aVideoSample);
|
||||
hr = E_FAIL;
|
||||
mozilla::mscom::EnsureMTA(
|
||||
[&]() -> void { hr = mTransform->Input(aVideoSample); });
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
RefPtr<IMFSample> sample;
|
||||
hr = CreateOutputSample(sample, texture);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
hr = mTransform->Output(&sample);
|
||||
hr = E_FAIL;
|
||||
mozilla::mscom::EnsureMTA(
|
||||
[&]() -> void { hr = mTransform->Output(&sample); });
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
}
|
||||
}
|
||||
|
@ -1029,14 +1048,19 @@ D3D11DXVA2Manager::CopyToBGRATexture(ID3D11Texture2D *aInTexture,
|
|||
|
||||
inputSample->AddBuffer(inputBuffer);
|
||||
|
||||
hr = mTransform->Input(inputSample);
|
||||
hr = E_FAIL;
|
||||
mozilla::mscom::EnsureMTA(
|
||||
[&]() -> void { hr = mTransform->Input(inputSample); });
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
RefPtr<IMFSample> outputSample;
|
||||
hr = CreateOutputSample(outputSample, texture);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
hr = mTransform->Output(&outputSample);
|
||||
hr = E_FAIL;
|
||||
mozilla::mscom::EnsureMTA(
|
||||
[&]() -> void { hr = mTransform->Output(&outputSample); });
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
texture.forget(aOutTexture);
|
||||
|
||||
|
@ -1062,6 +1086,11 @@ HRESULT ConfigureOutput(IMFMediaType* aOutput, void* aData)
|
|||
HRESULT
|
||||
D3D11DXVA2Manager::ConfigureForSize(uint32_t aWidth, uint32_t aHeight)
|
||||
{
|
||||
if (mConfiuredForSize && aWidth == mWidth && aHeight == mHeight) {
|
||||
// If the size hasn't changed, don't reconfigure.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
mWidth = aWidth;
|
||||
mHeight = aHeight;
|
||||
|
||||
|
@ -1081,7 +1110,10 @@ D3D11DXVA2Manager::ConfigureForSize(uint32_t aWidth, uint32_t aHeight)
|
|||
hr = inputType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
RefPtr<IMFAttributes> attr = mTransform->GetAttributes();
|
||||
RefPtr<IMFAttributes> attr;
|
||||
mozilla::mscom::EnsureMTA(
|
||||
[&]() -> void { attr = mTransform->GetAttributes(); });
|
||||
NS_ENSURE_TRUE(attr != nullptr, E_FAIL);
|
||||
|
||||
hr = attr->SetUINT32(MF_XVP_PLAYBACK_MODE, TRUE);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
@ -1103,9 +1135,15 @@ D3D11DXVA2Manager::ConfigureForSize(uint32_t aWidth, uint32_t aHeight)
|
|||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
gfx::IntSize size(mWidth, mHeight);
|
||||
hr = mTransform->SetMediaTypes(inputType, outputType, ConfigureOutput, &size);
|
||||
hr = E_FAIL;
|
||||
mozilla::mscom::EnsureMTA([&]() -> void {
|
||||
hr =
|
||||
mTransform->SetMediaTypes(inputType, outputType, ConfigureOutput, &size);
|
||||
});
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
mConfiuredForSize = true;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "WMFUtils.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/mscom/Utils.h"
|
||||
|
||||
#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
|
||||
|
||||
|
@ -26,6 +27,8 @@ MFTDecoder::~MFTDecoder()
|
|||
HRESULT
|
||||
MFTDecoder::Create(const GUID& aMFTClsID)
|
||||
{
|
||||
// Note: IMFTransform is documented to only be safe on MTA threads.
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
// Create the IMFTransform to do the decoding.
|
||||
HRESULT hr;
|
||||
hr = CoCreateInstance(aMFTClsID,
|
||||
|
@ -45,6 +48,7 @@ MFTDecoder::SetMediaTypes(IMFMediaType* aInputType,
|
|||
ConfigureOutputCallback aCallback,
|
||||
void* aData)
|
||||
{
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
mOutputType = aOutputType;
|
||||
|
||||
// Set the input type to the one the caller gave us...
|
||||
|
@ -69,6 +73,7 @@ MFTDecoder::SetMediaTypes(IMFMediaType* aInputType,
|
|||
already_AddRefed<IMFAttributes>
|
||||
MFTDecoder::GetAttributes()
|
||||
{
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
RefPtr<IMFAttributes> attr;
|
||||
HRESULT hr = mDecoder->GetAttributes(getter_AddRefs(attr));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
|
||||
|
@ -80,6 +85,7 @@ MFTDecoder::SetDecoderOutputType(bool aMatchAllAttributes,
|
|||
ConfigureOutputCallback aCallback,
|
||||
void* aData)
|
||||
{
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
NS_ENSURE_TRUE(mDecoder != nullptr, E_POINTER);
|
||||
|
||||
GUID currentSubtype = {0};
|
||||
|
@ -127,6 +133,7 @@ MFTDecoder::SetDecoderOutputType(bool aMatchAllAttributes,
|
|||
HRESULT
|
||||
MFTDecoder::SendMFTMessage(MFT_MESSAGE_TYPE aMsg, ULONG_PTR aData)
|
||||
{
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
NS_ENSURE_TRUE(mDecoder != nullptr, E_POINTER);
|
||||
HRESULT hr = mDecoder->ProcessMessage(aMsg, aData);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
@ -139,6 +146,7 @@ MFTDecoder::CreateInputSample(const uint8_t* aData,
|
|||
int64_t aTimestamp,
|
||||
RefPtr<IMFSample>* aOutSample)
|
||||
{
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
NS_ENSURE_TRUE(mDecoder != nullptr, E_POINTER);
|
||||
|
||||
HRESULT hr;
|
||||
|
@ -184,6 +192,7 @@ MFTDecoder::CreateInputSample(const uint8_t* aData,
|
|||
HRESULT
|
||||
MFTDecoder::CreateOutputSample(RefPtr<IMFSample>* aOutSample)
|
||||
{
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
NS_ENSURE_TRUE(mDecoder != nullptr, E_POINTER);
|
||||
|
||||
HRESULT hr;
|
||||
|
@ -210,6 +219,7 @@ MFTDecoder::CreateOutputSample(RefPtr<IMFSample>* aOutSample)
|
|||
HRESULT
|
||||
MFTDecoder::Output(RefPtr<IMFSample>* aOutput)
|
||||
{
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
NS_ENSURE_TRUE(mDecoder != nullptr, E_POINTER);
|
||||
|
||||
HRESULT hr;
|
||||
|
@ -275,6 +285,7 @@ MFTDecoder::Input(const uint8_t* aData,
|
|||
uint32_t aDataSize,
|
||||
int64_t aTimestamp)
|
||||
{
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
NS_ENSURE_TRUE(mDecoder != nullptr, E_POINTER);
|
||||
|
||||
RefPtr<IMFSample> input;
|
||||
|
@ -287,6 +298,7 @@ MFTDecoder::Input(const uint8_t* aData,
|
|||
HRESULT
|
||||
MFTDecoder::Input(IMFSample* aSample)
|
||||
{
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
HRESULT hr = mDecoder->ProcessInput(0, aSample, 0);
|
||||
if (hr == MF_E_NOTACCEPTING) {
|
||||
// MFT *already* has enough data to produce a sample. Retrieve it.
|
||||
|
@ -300,6 +312,7 @@ MFTDecoder::Input(IMFSample* aSample)
|
|||
HRESULT
|
||||
MFTDecoder::Flush()
|
||||
{
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
HRESULT hr = SendMFTMessage(MFT_MESSAGE_COMMAND_FLUSH, 0);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
|
@ -311,6 +324,7 @@ MFTDecoder::Flush()
|
|||
HRESULT
|
||||
MFTDecoder::GetOutputMediaType(RefPtr<IMFMediaType>& aMediaType)
|
||||
{
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
NS_ENSURE_TRUE(mDecoder, E_POINTER);
|
||||
return mDecoder->GetOutputCurrentType(0, getter_AddRefs(aMediaType));
|
||||
}
|
||||
|
|
|
@ -42,12 +42,17 @@ namespace mozilla {
|
|||
namespace wmf {
|
||||
|
||||
// If successful, loads all required WMF DLLs and calls the WMF MFStartup()
|
||||
// function.
|
||||
// function. This delegates the WMF MFStartup() call to the MTA thread if
|
||||
// the current thread is not MTA. This is to ensure we always interact with
|
||||
// WMF from threads with the same COM compartment model.
|
||||
HRESULT MFStartup();
|
||||
|
||||
// Calls the WMF MFShutdown() function. Call this once for every time
|
||||
// wmf::MFStartup() succeeds. Note: does not unload the WMF DLLs loaded by
|
||||
// MFStartup(); leaves them in memory to save I/O at next MFStartup() call.
|
||||
// This delegates the WMF MFShutdown() call to the MTA thread if the current
|
||||
// thread is not MTA. This is to ensure we always interact with
|
||||
// WMF from threads with the same COM compartment model.
|
||||
HRESULT MFShutdown();
|
||||
|
||||
// All functions below are wrappers around the corresponding WMF function,
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "nsWindowsHelpers.h"
|
||||
#include "prsystem.h"
|
||||
#include "nsIXULRuntime.h"
|
||||
#include "mozilla/mscom/EnsureMTA.h"
|
||||
|
||||
extern const GUID CLSID_WebmMfVpxDec;
|
||||
|
||||
|
@ -135,16 +136,22 @@ WMFDecoderModule::CreateAudioDecoder(const CreateDecoderParams& aParams)
|
|||
static bool
|
||||
CanCreateMFTDecoder(const GUID& aGuid)
|
||||
{
|
||||
if (FAILED(wmf::MFStartup())) {
|
||||
return false;
|
||||
}
|
||||
bool hasdecoder = false;
|
||||
{
|
||||
// The IMFTransform interface used by MFTDecoder is documented to require to
|
||||
// run on an MTA thread.
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ee892371(v=vs.85).aspx#components
|
||||
// Note: our normal SharedThreadPool task queues are initialized to MTA, but
|
||||
// the main thread (which calls in here from our CanPlayType implementation)
|
||||
// is not.
|
||||
bool canCreateDecoder = false;
|
||||
mozilla::mscom::EnsureMTA([&]() -> void {
|
||||
if (FAILED(wmf::MFStartup())) {
|
||||
return;
|
||||
}
|
||||
RefPtr<MFTDecoder> decoder(new MFTDecoder());
|
||||
hasdecoder = SUCCEEDED(decoder->Create(aGuid));
|
||||
}
|
||||
wmf::MFShutdown();
|
||||
return hasdecoder;
|
||||
canCreateDecoder = SUCCEEDED(decoder->Create(aGuid));
|
||||
wmf::MFShutdown();
|
||||
});
|
||||
return canCreateDecoder;
|
||||
}
|
||||
|
||||
template<const GUID& aGuid>
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "nsWindowsHelpers.h"
|
||||
#include <initguid.h>
|
||||
#include <stdint.h>
|
||||
#include "mozilla/mscom/EnsureMTA.h"
|
||||
|
||||
#ifdef WMF_MUST_DEFINE_AAC_MFT_CLSID
|
||||
// Some SDK versions don't define the AAC decoder CLSID.
|
||||
|
@ -220,14 +221,20 @@ MFStartup()
|
|||
// decltype is unusable for functions having default parameters
|
||||
DECL_FUNCTION_PTR(MFStartup, ULONG, DWORD);
|
||||
ENSURE_FUNCTION_PTR_(MFStartup, Mfplat.dll)
|
||||
return MFStartupPtr(MF_WIN7_VERSION, MFSTARTUP_FULL);
|
||||
|
||||
hr = E_FAIL;
|
||||
mozilla::mscom::EnsureMTA(
|
||||
[&]() -> void { hr = MFStartupPtr(MF_WIN7_VERSION, MFSTARTUP_FULL); });
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFShutdown()
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFShutdown, Mfplat.dll)
|
||||
return (MFShutdownPtr)();
|
||||
HRESULT hr = E_FAIL;
|
||||
mozilla::mscom::EnsureMTA([&]() -> void { hr = (MFShutdownPtr)(); });
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
|
|
Двоичный файл не отображается.
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -197,21 +197,6 @@ function AppendTrack(test, ms, track, token)
|
|||
Log(token, track.name + ": addSourceBuffer(" + track.type + ")");
|
||||
sb = ms.addSourceBuffer(track.type);
|
||||
sb.addEventListener("updateend", function() {
|
||||
if (ms.readyState == "ended") {
|
||||
/* We can get another updateevent as a result of calling ms.endOfStream() if
|
||||
the highest end time of our source buffers is different from that of the
|
||||
media source duration. Due to bug 1065207 this can happen because of
|
||||
inaccuracies in the frame duration calculations. Check if we are already
|
||||
"ended" and ignore the update event */
|
||||
Log(token, track.name + ": updateend when readyState already 'ended'");
|
||||
if (!resolved) {
|
||||
// Needed if decoder knows this was the last fragment and ended by itself.
|
||||
Log(token, track.name + ": but promise not resolved yet -> end of track");
|
||||
resolve();
|
||||
resolved = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
Log(token, track.name + ": updateend for " + fragmentFile + ", " + SourceBufferToString(sb));
|
||||
addNextFragment();
|
||||
});
|
||||
|
@ -222,7 +207,7 @@ function AppendTrack(test, ms, track, token)
|
|||
|
||||
//Returns a promise that is resolved when the media element is ready to have
|
||||
//its play() function called; when it's loaded MSE fragments.
|
||||
function LoadTest(test, elem, token)
|
||||
function LoadTest(test, elem, token, endOfStream = true)
|
||||
{
|
||||
if (!test.tracks) {
|
||||
ok(false, token + " test does not have a tracks list");
|
||||
|
@ -240,7 +225,9 @@ function LoadTest(test, elem, token)
|
|||
return AppendTrack(test, ms, track, token);
|
||||
})).then(function() {
|
||||
Log(token, "Tracks loaded, calling MediaSource.endOfStream()");
|
||||
ms.endOfStream();
|
||||
if (endOfStream) {
|
||||
ms.endOfStream();
|
||||
}
|
||||
resolve();
|
||||
}).catch(reject);
|
||||
}, {once: true});
|
||||
|
|
|
@ -72,6 +72,8 @@ support-files =
|
|||
bipbop-cenc-video2.m4s^headers^
|
||||
bipbop-cenc-videoinit.mp4
|
||||
bipbop-cenc-videoinit.mp4^headers^
|
||||
bipbop-cenc-video-10s.mp4
|
||||
bipbop-cenc-video-10s.mp4^headers^
|
||||
bipbop_225w_175kbps-cenc-audio-key1-1.m4s
|
||||
bipbop_225w_175kbps-cenc-audio-key1-1.m4s^headers^
|
||||
bipbop_225w_175kbps-cenc-audio-key1-2.m4s
|
||||
|
@ -747,6 +749,8 @@ skip-if = toolkit == 'android' # bug 1336166
|
|||
[test_delay_load.html]
|
||||
skip-if = android_version == '17' # android(bug 1232305)
|
||||
[test_duration_after_error.html]
|
||||
[test_eme_autoplay.html]
|
||||
skip-if = toolkit == 'android' # bug 1149374
|
||||
[test_eme_pssh_in_moof.html]
|
||||
skip-if = toolkit == 'android' # bug 1149374
|
||||
[test_eme_session_callable_value.html]
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test Encrypted Media Extensions</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
<script type="text/javascript" src="http://test1.mochi.test:8888/tests/dom/media/test/eme.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
var manager = new MediaTestManager;
|
||||
|
||||
var EMEmanifest = [
|
||||
{
|
||||
name:"bipbop 10s",
|
||||
tracks: [
|
||||
{
|
||||
name:"video",
|
||||
type:"video/mp4; codecs=\"avc1.4d4015\"",
|
||||
fragments:[ "bipbop-cenc-video-10s.mp4",
|
||||
]
|
||||
}
|
||||
],
|
||||
keys: {
|
||||
"7e571d037e571d037e571d037e571d11" : "7e5733337e5733337e5733337e573311",
|
||||
},
|
||||
sessionType:"temporary",
|
||||
sessionCount:1,
|
||||
duration:10.01
|
||||
},
|
||||
];
|
||||
|
||||
function startTest(test, token)
|
||||
{
|
||||
manager.started(token);
|
||||
|
||||
let v = document.createElement("video");
|
||||
v.controls = true;
|
||||
v.autoplay = true;
|
||||
|
||||
document.body.appendChild(v);
|
||||
|
||||
var eventCounts = { play: 0, playing: 0};
|
||||
function ForbiddenEvents(e) {
|
||||
var v = e.target;
|
||||
ok(v.readyState >= v.HAVE_FUTURE_DATA, "Must not have received event too early");
|
||||
is(eventCounts[e.type], 0, "event should have only be fired once");
|
||||
eventCounts[e.type]++;
|
||||
}
|
||||
// Log events for debugging.
|
||||
var events = ["suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
|
||||
"loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
|
||||
"waiting", "pause", "durationchange", "seeking", "seeked"];
|
||||
function logEvent(e) {
|
||||
info("got " + e.type + " event");
|
||||
}
|
||||
events.forEach(function(e) {
|
||||
v.addEventListener(e, logEvent);
|
||||
});
|
||||
v.addEventListener("play", ForbiddenEvents);
|
||||
v.addEventListener("playing", ForbiddenEvents);
|
||||
|
||||
var gotWaitingForKey = 0;
|
||||
|
||||
let waitForKey = new EMEPromise;
|
||||
v.addEventListener("waitingforkey", function() {
|
||||
gotWaitingForKey += 1;
|
||||
waitForKey.resolve();
|
||||
});
|
||||
|
||||
v.addEventListener("loadedmetadata", function() {
|
||||
ok(SpecialPowers.do_lookupGetter(v, "isEncrypted").apply(v),
|
||||
TimeStamp(token) + " isEncrypted should be true");
|
||||
is(v.isEncrypted, undefined, "isEncrypted should not be accessible from content");
|
||||
});
|
||||
|
||||
let finish = new EMEPromise;
|
||||
v.addEventListener("playing", function() {
|
||||
ok(true, TimeStamp(token) + " got playing event");
|
||||
// We expect only one waitingForKey as we delay until all sessions are ready.
|
||||
// I.e. one waitingForKey should be fired, after which, we process all sessions,
|
||||
// so it should not be possible to be blocked by a key after that point.
|
||||
ok(gotWaitingForKey == 1, "Expected number 1 wait, got: " + gotWaitingForKey);
|
||||
|
||||
finish.resolve();
|
||||
});
|
||||
|
||||
Promise.all([
|
||||
LoadInitData(v, test, token),
|
||||
CreateAndSetMediaKeys(v, test, token),
|
||||
LoadTest(test, v, token, false /* do not call endOfStream */),
|
||||
waitForKey.promise])
|
||||
.then(values => {
|
||||
let initData = values[0];
|
||||
return ProcessInitData(v, test, token, initData);
|
||||
})
|
||||
.then(sessions => {
|
||||
Log(token, "Updated all sessions, loading complete");
|
||||
finish.promise.then(() => CloseSessions(v, sessions));
|
||||
return finish.promise;
|
||||
})
|
||||
.catch(reason => ok(false, reason))
|
||||
.then(() => manager.finished(token));
|
||||
}
|
||||
|
||||
function beginTest() {
|
||||
manager.runTests(EMEmanifest, startTest);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SetupEMEPref(beginTest);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -507,48 +507,6 @@ private:
|
|||
nsChangeHint mComputedHint;
|
||||
};
|
||||
|
||||
// Get the nsBlockFrame which might contain ::first-letter/::first-line for the
|
||||
// given element. Will return null if there is no such blockframe.
|
||||
static nsBlockFrame*
|
||||
GetBlockForElement(const Element* aElement)
|
||||
{
|
||||
nsIFrame* frame = aElement->GetPrimaryFrame();
|
||||
if (!frame) {
|
||||
return nullptr;
|
||||
}
|
||||
// The first-letter frame will always be inside the content insertion frame,
|
||||
// which will always be a block if we have a first-letter frame at all.
|
||||
frame = frame->GetContentInsertionFrame();
|
||||
if (!frame) {
|
||||
// We're a leaf; certainly no first-letter frame.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!frame->IsFrameOfType(nsIFrame::eBlockFrame)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return static_cast<nsBlockFrame*>(frame);
|
||||
}
|
||||
|
||||
// Find the first-letter frame for the given element, if any. Returns null to
|
||||
// indicate there isn't one.
|
||||
static nsIFrame*
|
||||
FindFirstLetterFrameForElement(const Element* aElement)
|
||||
{
|
||||
nsBlockFrame* f = GetBlockForElement(aElement);
|
||||
return f ? f->GetFirstLetter() : nullptr;
|
||||
}
|
||||
|
||||
// Find the first-line frame for the given element, if any. Returns null to
|
||||
// indicate there isn't one.
|
||||
static nsIFrame*
|
||||
FindFirstLineFrameForElement(const Element* aElement)
|
||||
{
|
||||
nsBlockFrame* f = GetBlockForElement(aElement);
|
||||
return f ? f->GetFirstLineFrame() : nullptr;
|
||||
}
|
||||
|
||||
static void
|
||||
UpdateBackdropIfNeeded(nsIFrame* aFrame,
|
||||
ServoStyleSet& aStyleSet,
|
||||
|
@ -1004,37 +962,6 @@ ServoRestyleManager::SnapshotFor(Element* aElement)
|
|||
return *snapshot;
|
||||
}
|
||||
|
||||
/* static */ nsIFrame*
|
||||
ServoRestyleManager::FrameForPseudoElement(const Element* aElement,
|
||||
nsIAtom* aPseudoTagOrNull)
|
||||
{
|
||||
if (!aPseudoTagOrNull) {
|
||||
return nsLayoutUtils::GetStyleFrame(aElement);
|
||||
}
|
||||
|
||||
if (aPseudoTagOrNull == nsCSSPseudoElements::before) {
|
||||
Element* pseudoElement = nsLayoutUtils::GetBeforePseudo(aElement);
|
||||
return pseudoElement ? nsLayoutUtils::GetStyleFrame(pseudoElement) : nullptr;
|
||||
}
|
||||
|
||||
if (aPseudoTagOrNull == nsCSSPseudoElements::after) {
|
||||
Element* pseudoElement = nsLayoutUtils::GetAfterPseudo(aElement);
|
||||
return pseudoElement ? nsLayoutUtils::GetStyleFrame(pseudoElement) : nullptr;
|
||||
}
|
||||
|
||||
if (aPseudoTagOrNull == nsCSSPseudoElements::firstLetter) {
|
||||
return FindFirstLetterFrameForElement(aElement);
|
||||
}
|
||||
|
||||
if (aPseudoTagOrNull == nsCSSPseudoElements::firstLine) {
|
||||
return FindFirstLineFrameForElement(aElement);
|
||||
}
|
||||
|
||||
MOZ_CRASH("Unkown pseudo-element given to "
|
||||
"ServoRestyleManager::FrameForPseudoElement");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ServoRestyleManager::DoProcessPendingRestyles(ServoTraversalFlags aFlags)
|
||||
{
|
||||
|
|
|
@ -218,15 +218,6 @@ public:
|
|||
// this method accordingly (e.g. to ReparentStyleContextForFirstLine).
|
||||
nsresult ReparentStyleContext(nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Gets the appropriate frame given a content and a pseudo-element tag.
|
||||
*
|
||||
* Right now only supports a null tag, before or after. If the pseudo-element
|
||||
* is not null, the content needs to be an element.
|
||||
*/
|
||||
static nsIFrame* FrameForPseudoElement(const Element* aElement,
|
||||
nsIAtom* aPseudoTagOrNull);
|
||||
|
||||
/**
|
||||
* Clears the ServoElementData and HasDirtyDescendants from all elements
|
||||
* in the subtree rooted at aElement.
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
span {
|
||||
padding: 0em 1em;
|
||||
margin-left: 10px;
|
||||
font: 24px sans-serif;
|
||||
line-height: 2;
|
||||
clip-path: url(#path);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<span>The</span><br>
|
||||
<span>quick</span><br>
|
||||
<span>orange fox</span>
|
||||
|
||||
<svg height="0">
|
||||
<defs>
|
||||
<clipPath id="path" clipPathUnits="objectBoundingBox">
|
||||
<rect x="0" y="0" width="1" height="0.5"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
|
@ -1,34 +0,0 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test of box-decoration-break:clone with clip-path</title>
|
||||
<style>
|
||||
.clone {
|
||||
box-decoration-break: clone;
|
||||
}
|
||||
span {
|
||||
padding: 0em 1em;
|
||||
margin-left: 10px;
|
||||
font: 24px sans-serif;
|
||||
line-height: 2;
|
||||
clip-path: url(#path);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<span class="clone">The<br>quick<br>orange fox</span>
|
||||
|
||||
<svg height="0">
|
||||
<defs>
|
||||
<clipPath id="path" clipPathUnits="objectBoundingBox">
|
||||
<rect x="0" y="0" width="1" height="0.5"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
|
@ -1,14 +0,0 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
span {
|
||||
padding: 0em 1em;
|
||||
margin-left: 10px;
|
||||
font: 24px sans-serif;
|
||||
line-height: 2;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<span>The</span>
|
||||
</body>
|
|
@ -1,31 +0,0 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test of box-decoration-break:slice with clip-path</title>
|
||||
<style>
|
||||
span {
|
||||
padding: 0em 1em;
|
||||
margin-left: 10px;
|
||||
font: 24px sans-serif;
|
||||
line-height: 2;
|
||||
clip-path: url(#path);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<span>The<br>quick<br>orange fox</span>
|
||||
|
||||
<svg height="0">
|
||||
<defs>
|
||||
<clipPath id="path" clipPathUnits="objectBoundingBox">
|
||||
<rect x="0" y="0" width="1" height="0.3"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
|
@ -56,9 +56,6 @@ skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-differenc
|
|||
|
||||
== border-radius-01.html pass.svg
|
||||
|
||||
== box-decoration-break-clone.html box-decoration-break-clone-ref.html
|
||||
== box-decoration-break-slice.html box-decoration-break-slice-ref.html
|
||||
|
||||
== clip-01.svg pass.svg
|
||||
== clip-02a.svg clip-02-ref.svg
|
||||
== clip-02b.svg clip-02-ref.svg
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<style>
|
||||
.clip {
|
||||
clip-path:url(#path);
|
||||
}
|
||||
span {
|
||||
font: 24px sans-serif;
|
||||
line-height: 2;
|
||||
color: lime;
|
||||
background: lime;
|
||||
}
|
||||
br {
|
||||
line-height: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Box-Decoration-Break: Clone</h2>
|
||||
<span class="clip">The</span><br />
|
||||
<span class="clip">quick</span><br />
|
||||
<span class="clip">orange fox</span>
|
||||
|
||||
<h2>Box-Decoration-Break: Slice</h2>
|
||||
<span>The</span>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="0">
|
||||
<defs>
|
||||
<clipPath id="path" clipPathUnits="objectBoundingBox">
|
||||
<rect x="0" y="0" width="1" height="0.3"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,41 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Test of box-decoration-break with clip-path: url</title>
|
||||
<style>
|
||||
.clone {
|
||||
box-decoration-break: clone;
|
||||
}
|
||||
span {
|
||||
font: 24px sans-serif;
|
||||
line-height: 2;
|
||||
color: lime;
|
||||
background: lime;
|
||||
clip-path: url(#path);
|
||||
}
|
||||
br {
|
||||
line-height: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Box-Decoration-Break: Clone</h2>
|
||||
<span class="clone">The<br />quick<br />orange fox</span>
|
||||
|
||||
<h2>Box-Decoration-Break: Slice</h2>
|
||||
<span>The<br />quick<br />orange fox</span>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="0">
|
||||
<defs>
|
||||
<clipPath id="path" clipPathUnits="objectBoundingBox">
|
||||
<rect x="0" y="0" width="1" height="0.3"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,27 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<style>
|
||||
span {
|
||||
font: 24px sans-serif;
|
||||
line-height: 2;
|
||||
color: lime;
|
||||
background: lime;
|
||||
}
|
||||
br {
|
||||
line-height: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Box-Decoration-Break: Clone</h2>
|
||||
<span>The</span><br />
|
||||
<span>quick</span><br />
|
||||
<span>orange fox</span>
|
||||
|
||||
<h2>Box-Decoration-Break: Slice</h2>
|
||||
<span>The</span><br />
|
||||
<span>quick</span><br />
|
||||
<span>orange fox</span>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,33 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Test of box-decoration-break with filter</title>
|
||||
<style>
|
||||
.clone {
|
||||
box-decoration-break: clone;
|
||||
}
|
||||
span {
|
||||
font: 24px sans-serif;
|
||||
line-height: 2;
|
||||
color: lime;
|
||||
background: lime;
|
||||
filter: blur(0px);
|
||||
}
|
||||
br {
|
||||
line-height: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Box-Decoration-Break: Clone</h2>
|
||||
<span class="clone">The<br />quick<br />orange fox</span>
|
||||
|
||||
<h2>Box-Decoration-Break: Slice</h2>
|
||||
<span>The<br />quick<br />orange fox</span>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,42 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Test of box-decoration-break with clip-path: url and filter</title>
|
||||
<style>
|
||||
.clone {
|
||||
box-decoration-break: clone;
|
||||
}
|
||||
span {
|
||||
font: 24px sans-serif;
|
||||
line-height: 2;
|
||||
color: lime;
|
||||
background: lime;
|
||||
clip-path: url(#path);
|
||||
filter: blur(0px);
|
||||
}
|
||||
br {
|
||||
line-height: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Box-Decoration-Break: Clone</h2>
|
||||
<span class="clone">The<br />quick<br />orange fox</span>
|
||||
|
||||
<h2>Box-Decoration-Break: Slice</h2>
|
||||
<span>The<br />quick<br />orange fox</span>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="0">
|
||||
<defs>
|
||||
<clipPath id="path" clipPathUnits="objectBoundingBox">
|
||||
<rect x="0" y="0" width="1" height="0.3"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
|
@ -45,3 +45,8 @@ fuzzy(1,5000) == mask-clipPath-opacity-01d.xhtml mask-clipPath-opacity-01-ref.xh
|
|||
fuzzy(1,5000) == mask-clipPath-opacity-01e.xhtml mask-clipPath-opacity-01-ref.xhtml
|
||||
|
||||
== transform-outer-svg-01.xhtml transform-outer-svg-01-ref.xhtml
|
||||
|
||||
# box-decoration-break tests
|
||||
fuzzy-if(Android,4,10) == box-decoration-break-01.xhtml box-decoration-break-01-ref.xhtml
|
||||
fuzzy(56,14) == box-decoration-break-02.xhtml box-decoration-break-02-ref.xhtml
|
||||
fuzzy(67,234) == box-decoration-break-03.xhtml box-decoration-break-01-ref.xhtml
|
||||
|
|
|
@ -354,7 +354,8 @@ SERVO_BINDING_FUNC(Servo_DeclarationBlock_GetCssText, void,
|
|||
nsAString* result)
|
||||
SERVO_BINDING_FUNC(Servo_DeclarationBlock_SerializeOneValue, void,
|
||||
RawServoDeclarationBlockBorrowed declarations,
|
||||
nsCSSPropertyID property, nsAString* buffer)
|
||||
nsCSSPropertyID property, nsAString* buffer,
|
||||
ServoStyleContextBorrowedOrNull computed_values)
|
||||
SERVO_BINDING_FUNC(Servo_DeclarationBlock_Count, uint32_t,
|
||||
RawServoDeclarationBlockBorrowed declarations)
|
||||
SERVO_BINDING_FUNC(Servo_DeclarationBlock_GetNthProperty, bool,
|
||||
|
|
|
@ -372,30 +372,6 @@ Gecko_NoteAnimationOnlyDirtyElement(RawGeckoElementBorrowed aElement)
|
|||
const_cast<Element*>(aElement)->NoteAnimationOnlyDirtyForServo();
|
||||
}
|
||||
|
||||
nsStyleContext*
|
||||
Gecko_GetStyleContext(RawGeckoElementBorrowed aElement,
|
||||
nsIAtom* aPseudoTagOrNull)
|
||||
{
|
||||
nsIFrame* relevantFrame =
|
||||
ServoRestyleManager::FrameForPseudoElement(aElement, aPseudoTagOrNull);
|
||||
if (relevantFrame) {
|
||||
return relevantFrame->StyleContext();
|
||||
}
|
||||
|
||||
if (aPseudoTagOrNull) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// FIXME(emilio): Is there a shorter path?
|
||||
nsIPresShell* shell = aElement->OwnerDoc()->GetShell();
|
||||
NS_ENSURE_TRUE(shell, nullptr);
|
||||
nsCSSFrameConstructor* fc = shell->GetPresContext()->FrameConstructor();
|
||||
|
||||
// NB: This is only called for CalcStyleDifference, and we handle correctly
|
||||
// the display: none case since Servo still has the older style.
|
||||
return fc->GetDisplayContentsStyleFor(aElement);
|
||||
}
|
||||
|
||||
CSSPseudoElementType
|
||||
Gecko_GetImplementedPseudo(RawGeckoElementBorrowed aElement)
|
||||
{
|
||||
|
|
|
@ -384,10 +384,6 @@ void Gecko_NoteDirtyElement(RawGeckoElementBorrowed element);
|
|||
void Gecko_NoteAnimationOnlyDirtyElement(RawGeckoElementBorrowed element);
|
||||
|
||||
// Incremental restyle.
|
||||
// Also, we might want a ComputedValues to ComputedValues API for animations?
|
||||
// Not if we do them in Gecko...
|
||||
nsStyleContext* Gecko_GetStyleContext(RawGeckoElementBorrowed element,
|
||||
nsIAtom* aPseudoTagOrNull);
|
||||
mozilla::CSSPseudoElementType Gecko_GetImplementedPseudo(RawGeckoElementBorrowed element);
|
||||
// We'd like to return `nsChangeHint` here, but bindgen bitfield enums don't
|
||||
// work as return values with the Linux 32-bit ABI at the moment because
|
||||
|
|
|
@ -71,6 +71,7 @@ support-files = file_animations_playbackrate.html
|
|||
support-files = file_animations_reverse.html
|
||||
[test_animations_styles_on_event.html]
|
||||
support-files = file_animations_styles_on_event.html
|
||||
[test_animations_variable_changes.html]
|
||||
[test_animations_with_disabled_properties.html]
|
||||
support-files = file_animations_with_disabled_properties.html
|
||||
[test_any_dynamic.html]
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>Tests that animations respond to changes to variables</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../testcommon.js"></script>
|
||||
<style>
|
||||
:root {
|
||||
--width: 100px;
|
||||
}
|
||||
.wider {
|
||||
--width: 200px;
|
||||
}
|
||||
@keyframes widen {
|
||||
to { margin-left: var(--width) }
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
|
||||
test(() => {
|
||||
const div = document.createElement('div');
|
||||
document.body.append(div);
|
||||
|
||||
div.style.animation = 'widen step-start 100s';
|
||||
assert_equals(getComputedStyle(div).marginLeft, '100px',
|
||||
'Animation value before updating CSS variable');
|
||||
|
||||
div.classList.add('wider');
|
||||
|
||||
assert_equals(getComputedStyle(div).marginLeft, '200px',
|
||||
'Animation value after updating CSS variable');
|
||||
|
||||
div.remove();
|
||||
}, 'Animation reflects changes to custom properties');
|
||||
|
||||
test(() => {
|
||||
const parent = document.createElement('div');
|
||||
const child = document.createElement('div');
|
||||
parent.append(child);
|
||||
document.body.append(parent);
|
||||
|
||||
child.style.animation = 'widen step-start 100s';
|
||||
assert_equals(getComputedStyle(child).marginLeft, '100px',
|
||||
'Animation value before updating CSS variable');
|
||||
|
||||
parent.classList.add('wider');
|
||||
|
||||
assert_equals(getComputedStyle(child).marginLeft, '200px',
|
||||
'Animation value after updating CSS variable');
|
||||
|
||||
parent.remove();
|
||||
child.remove();
|
||||
}, 'Animation reflect changes to custom properties on parent');
|
||||
|
||||
</script>
|
||||
</body>
|
|
@ -465,7 +465,14 @@ nsSVGClipPathFrame::GetClipPathTransform(nsIFrame* aClippedFrame)
|
|||
nsSVGEnum* clipPathUnits =
|
||||
&content->mEnumAttributes[SVGClipPathElement::CLIPPATHUNITS];
|
||||
|
||||
return nsSVGUtils::AdjustMatrixForUnits(tm, clipPathUnits, aClippedFrame);
|
||||
uint32_t flags =
|
||||
nsSVGUtils::eBBoxIncludeFillGeometry |
|
||||
(aClippedFrame->StyleBorder()->mBoxDecorationBreak == StyleBoxDecorationBreak::Clone
|
||||
? nsSVGUtils::eIncludeOnlyCurrentFrameForNonSVGElement
|
||||
: 0);
|
||||
|
||||
return nsSVGUtils::AdjustMatrixForUnits(tm, clipPathUnits,
|
||||
aClippedFrame, flags);
|
||||
}
|
||||
|
||||
SVGBBox
|
||||
|
|
|
@ -217,7 +217,8 @@ nsSVGIntegrationUtils::GetSVGCoordContextForNonSVGFrame(nsIFrame* aNonSVGFrame)
|
|||
}
|
||||
|
||||
gfxRect
|
||||
nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(nsIFrame* aNonSVGFrame)
|
||||
nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(nsIFrame* aNonSVGFrame,
|
||||
bool aUnionContinuations)
|
||||
{
|
||||
// Except for nsSVGOuterSVGFrame, we shouldn't be getting here with SVG
|
||||
// frames at all. This function is for elements that are laid out using the
|
||||
|
@ -230,15 +231,12 @@ nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(nsIFrame* aNonSVGFrame)
|
|||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::FirstContinuationOrIBSplitSibling(aNonSVGFrame);
|
||||
// 'r' is in "user space":
|
||||
nsRect r;
|
||||
if (aNonSVGFrame->StyleBorder()->mBoxDecorationBreak == StyleBoxDecorationBreak::Clone) {
|
||||
r = GetPreEffectsVisualOverflow(firstFrame, aNonSVGFrame,
|
||||
GetOffsetToBoundingBox(firstFrame));
|
||||
} else {
|
||||
r = GetPreEffectsVisualOverflowUnion(firstFrame, nullptr, nsRect(),
|
||||
GetOffsetToBoundingBox(firstFrame),
|
||||
false);
|
||||
}
|
||||
nsRect r = (aUnionContinuations)
|
||||
? GetPreEffectsVisualOverflowUnion(firstFrame, nullptr, nsRect(),
|
||||
GetOffsetToBoundingBox(firstFrame),
|
||||
false)
|
||||
: GetPreEffectsVisualOverflow(firstFrame, aNonSVGFrame,
|
||||
GetOffsetToBoundingBox(firstFrame));
|
||||
|
||||
return nsLayoutUtils::RectToGfxRect(r,
|
||||
aNonSVGFrame->PresContext()->AppUnitsPerCSSPixel());
|
||||
|
|
|
@ -78,12 +78,13 @@ public:
|
|||
* "bbox" for the element they're being applied to in order to make decisions
|
||||
* about positioning, and to resolve various lengths against. This method
|
||||
* provides the "bbox" for non-SVG frames. The bbox returned is in CSS px
|
||||
* units, and is the union of all aNonSVGFrame's continuations' overflow
|
||||
* areas, relative to the top-left of the union of all aNonSVGFrame's
|
||||
* units, and aUnionContinuations decide whether bbox contains the area of
|
||||
* current frame only or the union of all aNonSVGFrame's continuations'
|
||||
* overflow areas, relative to the top-left of the union of all aNonSVGFrame's
|
||||
* continuations' border box rects.
|
||||
*/
|
||||
static gfxRect
|
||||
GetSVGBBoxForNonSVGFrame(nsIFrame* aNonSVGFrame);
|
||||
GetSVGBBoxForNonSVGFrame(nsIFrame* aNonSVGFrame, bool aUnionContinuations);
|
||||
|
||||
/**
|
||||
* Used to adjust a frame's pre-effects visual overflow rect to take account
|
||||
|
|
|
@ -226,6 +226,12 @@ nsSVGMaskFrame::GetMaskTransform(nsIFrame* aMaskedFrame)
|
|||
nsSVGEnum* maskContentUnits =
|
||||
&content->mEnumAttributes[SVGMaskElement::MASKCONTENTUNITS];
|
||||
|
||||
uint32_t flags =
|
||||
nsSVGUtils::eBBoxIncludeFillGeometry |
|
||||
(aMaskedFrame->StyleBorder()->mBoxDecorationBreak == StyleBoxDecorationBreak::Clone
|
||||
? nsSVGUtils::eIncludeOnlyCurrentFrameForNonSVGElement
|
||||
: 0);
|
||||
|
||||
return nsSVGUtils::AdjustMatrixForUnits(gfxMatrix(), maskContentUnits,
|
||||
aMaskedFrame);
|
||||
aMaskedFrame, flags);
|
||||
}
|
||||
|
|
|
@ -1099,7 +1099,10 @@ nsSVGUtils::GetBBox(nsIFrame* aFrame, uint32_t aFlags,
|
|||
(isOuterSVG && (aFlags & eUseFrameBoundsForOuterSVG))) {
|
||||
// An HTML element or an SVG outer frame.
|
||||
MOZ_ASSERT(!hasSVGLayout);
|
||||
return nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(aFrame);
|
||||
bool onlyCurrentFrame = aFlags & eIncludeOnlyCurrentFrameForNonSVGElement;
|
||||
return nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(
|
||||
aFrame,
|
||||
/* aUnionContinuations = */ !onlyCurrentFrame);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(svg);
|
||||
|
@ -1296,11 +1299,12 @@ nsSVGUtils::CanOptimizeOpacity(nsIFrame *aFrame)
|
|||
gfxMatrix
|
||||
nsSVGUtils::AdjustMatrixForUnits(const gfxMatrix &aMatrix,
|
||||
nsSVGEnum *aUnits,
|
||||
nsIFrame *aFrame)
|
||||
nsIFrame *aFrame,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
if (aFrame &&
|
||||
aUnits->GetAnimValue() == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
|
||||
gfxRect bbox = GetBBox(aFrame);
|
||||
gfxRect bbox = GetBBox(aFrame, aFlags);
|
||||
gfxMatrix tm = aMatrix;
|
||||
tm.PreTranslate(gfxPoint(bbox.X(), bbox.Y()));
|
||||
tm.PreScale(bbox.Width(), bbox.Height());
|
||||
|
|
|
@ -379,10 +379,13 @@ public:
|
|||
* bottom right of its bbox).
|
||||
*
|
||||
* If the bbox is empty, this will return a singular matrix.
|
||||
*
|
||||
* @param aFlags One or more of the BBoxFlags values defined below.
|
||||
*/
|
||||
static gfxMatrix AdjustMatrixForUnits(const gfxMatrix &aMatrix,
|
||||
nsSVGEnum *aUnits,
|
||||
nsIFrame *aFrame);
|
||||
nsIFrame *aFrame,
|
||||
uint32_t aFlags);
|
||||
|
||||
enum BBoxFlags {
|
||||
eBBoxIncludeFill = 1 << 0,
|
||||
|
@ -392,11 +395,15 @@ public:
|
|||
eBBoxIncludeMarkers = 1 << 4,
|
||||
eBBoxIncludeClipped = 1 << 5,
|
||||
// Normally a getBBox call on outer-<svg> should only return the
|
||||
// bounds of the elements children. This flag will cause the
|
||||
// bounds of the elements children. This flag will cause the
|
||||
// element's bounds to be returned instead.
|
||||
eUseFrameBoundsForOuterSVG = 1 << 6,
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect
|
||||
eForGetClientRects = 1 << 7,
|
||||
// If the given frame is an HTML element, only include the region of the
|
||||
// given frame, instead of all continuations of it, while computing bbox if
|
||||
// this flag is set.
|
||||
eIncludeOnlyCurrentFrameForNonSVGElement = 1 << 8,
|
||||
};
|
||||
/**
|
||||
* This function in primarily for implementing the SVG DOM function getBBox()
|
||||
|
@ -410,7 +417,7 @@ public:
|
|||
* obtained.
|
||||
* @param aFlags One or more of the BBoxFlags values defined above.
|
||||
* @param aToBoundsSpace If not specified the returned rect is in aFrame's
|
||||
* element's "user space". A matrix can optionally be pass to specify a
|
||||
* element's "user space". A matrix can optionally be pass to specify a
|
||||
* transform from aFrame's user space to the bounds space of interest
|
||||
* (typically this will be the ancestor nsSVGOuterSVGFrame, but it could be
|
||||
* to any other coordinate space).
|
||||
|
|
|
@ -59,7 +59,10 @@ endif
|
|||
# builds. It is called from the tinderbox scripts. Alter it with caution.
|
||||
|
||||
installers-%: IS_LANGUAGE_REPACK=1
|
||||
installers-%: clobber-stage repackage-zip-%
|
||||
installers-%:
|
||||
@$(MAKE) clobber-stage
|
||||
@$(MAKE) libs-$*
|
||||
@$(MAKE) repackage-zip-$*
|
||||
@echo 'repackaging done'
|
||||
|
||||
# When we unpack fennec on MacOS X the platform.ini and application.ini are in slightly
|
||||
|
|
|
@ -45,6 +45,10 @@ this.initTestLogging = function initTestLogging(level) {
|
|||
log.ownAppenders = [appender];
|
||||
log.updateAppenders();
|
||||
|
||||
// SQLite logging is noisy in these tests - we make it quiet by default
|
||||
// (although individual tests are free to bump it later)
|
||||
Log.repository.getLogger("Sqlite").level = Log.Level.Info;
|
||||
|
||||
return logStats;
|
||||
}
|
||||
|
||||
|
|
|
@ -1261,11 +1261,16 @@ SyncEngine.prototype = {
|
|||
}
|
||||
}
|
||||
|
||||
// Mobile: check if we got the maximum that we requested; get the rest if so.
|
||||
// History: check if we got the maximum that we requested; get the rest if so.
|
||||
if (handled.length == newitems.limit) {
|
||||
// XXX - this block appears to have no test coverage (eg, throwing here,
|
||||
// or commenting the entire block causes no tests to fail.)
|
||||
// See bug 1368951 comment 3 for some insightful analysis of why this
|
||||
// might not be doing what we expect anyway, so it may be the case that
|
||||
// this needs both fixing *and* tests.
|
||||
let guidColl = new Collection(this.engineURL, null, this.service);
|
||||
|
||||
// Sort and limit so that on mobile we only get the last X records.
|
||||
// Sort and limit so that we only get the last X records.
|
||||
guidColl.limit = this.downloadLimit;
|
||||
guidColl.newer = this.lastSync;
|
||||
|
||||
|
@ -1735,6 +1740,7 @@ SyncEngine.prototype = {
|
|||
// Remove the key for future uses
|
||||
delete this._delete[key];
|
||||
|
||||
this._log.trace("doing post-sync deletions", {key, val});
|
||||
// Send a simple delete for the property
|
||||
if (key != "ids" || val.length <= 100)
|
||||
await doDelete(key, val);
|
||||
|
|
|
@ -249,6 +249,7 @@ ServerCollection.prototype = {
|
|||
* @return the provided WBO.
|
||||
*/
|
||||
insertWBO: function insertWBO(wbo) {
|
||||
this.timestamp = Math.max(this.timestamp, wbo.modified);
|
||||
return this._wbos[wbo.id] = wbo;
|
||||
},
|
||||
|
||||
|
@ -445,7 +446,7 @@ ServerCollection.prototype = {
|
|||
if (nextOffset) {
|
||||
response.setHeader("X-Weave-Next-Offset", "" + nextOffset);
|
||||
}
|
||||
response.setHeader("X-Last-Modified", "" + this.timestamp);
|
||||
response.setHeader("X-Last-Modified", "" + self.timestamp);
|
||||
break;
|
||||
|
||||
case "POST":
|
||||
|
@ -466,16 +467,18 @@ ServerCollection.prototype = {
|
|||
response.setHeader("X-Weave-Timestamp",
|
||||
"" + new_timestamp(),
|
||||
false);
|
||||
response.setStatusLine(request.httpVersion, statusCode, status);
|
||||
response.bodyOutputStream.write(body, body.length);
|
||||
|
||||
// Update the collection timestamp to the appropriate modified time.
|
||||
// This is either a value set by the handler, or the current time.
|
||||
if (request.method != "GET") {
|
||||
this.timestamp = (response.newModified >= 0) ?
|
||||
self.timestamp = (response.newModified >= 0) ?
|
||||
response.newModified :
|
||||
new_timestamp();
|
||||
}
|
||||
response.setHeader("X-Last-Modified", "" + self.timestamp, false);
|
||||
|
||||
response.setStatusLine(request.httpVersion, statusCode, status);
|
||||
response.bodyOutputStream.write(body, body.length);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -492,6 +495,12 @@ function sync_httpd_setup(handlers) {
|
|||
|
||||
/*
|
||||
* Track collection modified times. Return closures.
|
||||
*
|
||||
* XXX - DO NOT USE IN NEW TESTS
|
||||
*
|
||||
* This code has very limited and very hacky timestamp support - the test
|
||||
* server now has more complete and correct support - using this helper
|
||||
* may cause strangeness wrt timestamp headers and 412 responses.
|
||||
*/
|
||||
function track_collections_helper() {
|
||||
|
||||
|
@ -942,6 +951,25 @@ SyncServer.prototype = {
|
|||
}
|
||||
let [, collection, wboID] = match;
|
||||
let coll = this.getCollection(username, collection);
|
||||
|
||||
let checkXIUSFailure = () => {
|
||||
if (req.hasHeader("x-if-unmodified-since")) {
|
||||
let xius = parseFloat(req.getHeader("x-if-unmodified-since"));
|
||||
// Sadly the way our tests are setup, we often end up with xius of
|
||||
// zero (typically when syncing just one engine, so the date from
|
||||
// info/collections isn't used) - so we allow that to work.
|
||||
// Further, the Python server treats non-existing collections as
|
||||
// having a timestamp of 0.
|
||||
let collTimestamp = coll ? coll.timestamp : 0;
|
||||
if (xius && xius < collTimestamp) {
|
||||
this._log.info(`x-if-unmodified-since mismatch - request wants ${xius} but our collection has ${collTimestamp}`);
|
||||
respond(412, "precondition failed", "precondition failed");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (req.method) {
|
||||
case "GET": {
|
||||
if (!coll) {
|
||||
|
@ -949,9 +977,9 @@ SyncServer.prototype = {
|
|||
respond(404, "Not found", "Not found");
|
||||
return undefined;
|
||||
}
|
||||
// *cries inside*: Bug 687299 - now fixed, so apparently the real
|
||||
// sync server *will* 404 in this case - bug 1347807 is to change
|
||||
// this to a 404 and fix a handful of test failures it causes.
|
||||
// *cries inside*: - apparently the real sync server returned 200
|
||||
// here for some time, then returned 404 for some time (bug 687299),
|
||||
// and now is back to 200 (bug 963332).
|
||||
respond(200, "OK", "[]");
|
||||
return undefined;
|
||||
}
|
||||
|
@ -965,12 +993,14 @@ SyncServer.prototype = {
|
|||
}
|
||||
return wbo.handler()(req, resp);
|
||||
}
|
||||
// TODO: implement handling of X-If-Unmodified-Since for write verbs.
|
||||
case "DELETE": {
|
||||
if (!coll) {
|
||||
respond(200, "OK", "{}");
|
||||
return undefined;
|
||||
}
|
||||
if (checkXIUSFailure()) {
|
||||
return undefined;
|
||||
}
|
||||
if (wboID) {
|
||||
let wbo = coll.wbo(wboID);
|
||||
if (wbo) {
|
||||
|
@ -1011,11 +1041,35 @@ SyncServer.prototype = {
|
|||
}
|
||||
return undefined;
|
||||
}
|
||||
case "POST":
|
||||
case "PUT":
|
||||
// PUT and POST have slightly different XIUS semantics - for PUT,
|
||||
// the check is against the item, whereas for POST it is against
|
||||
// the collection. So first, a special-case for PUT.
|
||||
if (req.hasHeader("x-if-unmodified-since")) {
|
||||
let xius = parseFloat(req.getHeader("x-if-unmodified-since"));
|
||||
// treat and xius of zero as if it wasn't specified - this happens
|
||||
// in some of our tests for a new collection.
|
||||
if (xius > 0) {
|
||||
let wbo = coll.wbo(wboID);
|
||||
if (xius < wbo.modified) {
|
||||
this._log.info(`x-if-unmodified-since mismatch - request wants ${xius} but wbo has ${wbo.modified}`);
|
||||
respond(412, "precondition failed", "precondition failed");
|
||||
return undefined;
|
||||
}
|
||||
wbo.handler()(req, resp);
|
||||
coll.timestamp = resp.newModified;
|
||||
return resp;
|
||||
}
|
||||
}
|
||||
// fall through to post.
|
||||
case "POST":
|
||||
if (checkXIUSFailure()) {
|
||||
return undefined;
|
||||
}
|
||||
if (!coll) {
|
||||
coll = this.createCollection(username, collection);
|
||||
}
|
||||
|
||||
if (wboID) {
|
||||
let wbo = coll.wbo(wboID);
|
||||
if (!wbo) {
|
||||
|
|
|
@ -228,11 +228,12 @@ add_task(async function test_disabled_install_semantics() {
|
|||
// are sane.
|
||||
restartManager();
|
||||
|
||||
let collection = server.getCollection(USER, "addons");
|
||||
engine.lastModified = collection.timestamp;
|
||||
await engine._sync();
|
||||
|
||||
// The client should not upload a new record. The old record should be
|
||||
// retained and unmodified.
|
||||
let collection = server.getCollection(USER, "addons");
|
||||
do_check_eq(1, collection.count());
|
||||
|
||||
let payload = collection.payloads()[0];
|
||||
|
|
|
@ -290,7 +290,8 @@ add_task(async function test_dupe_reparented_locally_changed_bookmark() {
|
|||
};
|
||||
|
||||
let deltaSeconds = 500;
|
||||
collection.insert(newGUID, encryptPayload(to_apply), Date.now() / 1000 + deltaSeconds);
|
||||
let newWBO = collection.insert(newGUID, encryptPayload(to_apply), Date.now() / 1000 + deltaSeconds);
|
||||
do_print(`new duplicate of ${bmk1_guid} is ${newGUID}`);
|
||||
|
||||
// Make a change to the bookmark that's a dupe, and set the modification
|
||||
// time further in the future than the incoming record. This will cause
|
||||
|
@ -303,7 +304,10 @@ add_task(async function test_dupe_reparented_locally_changed_bookmark() {
|
|||
});
|
||||
|
||||
_("Syncing so new dupe record is processed");
|
||||
engine.lastSync = engine.lastSync - 5;
|
||||
// We need to take care to only sync the one new record - if we also see
|
||||
// our local item as incoming the test fails - bug 1368608.
|
||||
engine.lastSync = newWBO.modified - 0.000001;
|
||||
engine.lastModified = null;
|
||||
await engine.sync();
|
||||
|
||||
// We should have logically deleted the dupe record.
|
||||
|
@ -311,7 +315,7 @@ add_task(async function test_dupe_reparented_locally_changed_bookmark() {
|
|||
ok(getServerRecord(collection, bmk1_guid).deleted);
|
||||
// and physically removed from the local store.
|
||||
await promiseNoLocalItem(bmk1_guid);
|
||||
// The original folder still longer has the item
|
||||
// The original folder still has the item
|
||||
equal((await getFolderChildrenIDs(folder1_id)).length, 1);
|
||||
// The second folder does not.
|
||||
equal((await getFolderChildrenIDs(folder2_id)).length, 0);
|
||||
|
|
|
@ -750,7 +750,10 @@ add_task(async function test_sync_dateAdded() {
|
|||
|
||||
let bzguid = await PlacesUtils.promiseItemGuid(bzid);
|
||||
|
||||
|
||||
// last sync did a POST, which doesn't advance its lastModified value.
|
||||
// Next sync of the engine doesn't hit info/collections, so lastModified
|
||||
// remains stale. Setting it to null side-steps that.
|
||||
engine.lastModified = null;
|
||||
await sync_engine_and_validate_telem(engine, false);
|
||||
|
||||
let newRecord2 = await store.createRecord(item2GUID);
|
||||
|
@ -764,8 +767,8 @@ add_task(async function test_sync_dateAdded() {
|
|||
|
||||
item2.dateAdded += 10000;
|
||||
collection.insert(item2GUID, encryptPayload(item2.cleartext), now / 1000 - 10);
|
||||
engine.lastSync = now / 1000 - 20;
|
||||
|
||||
engine.lastModified = null;
|
||||
await sync_engine_and_validate_telem(engine, false);
|
||||
|
||||
let newerRecord2 = await store.createRecord(item2GUID);
|
||||
|
|
|
@ -140,6 +140,7 @@ async function resolveConflict(engine, collection, timestamp, buildTree,
|
|||
collection.insert(record.id, encryptPayload(record), timestamp);
|
||||
}
|
||||
|
||||
engine.lastModified = collection.timestamp;
|
||||
await sync_engine_and_validate_telem(engine, false);
|
||||
|
||||
let expectedTree = buildTree(guids);
|
||||
|
|
|
@ -482,10 +482,12 @@ add_task(async function test_repair_server_deleted() {
|
|||
await validationPromise;
|
||||
|
||||
// Now we will reach into the server and create a tombstone for that bookmark
|
||||
// but with a last-modified in the past - this way our sync isn't going to
|
||||
// pick up the record.
|
||||
server.insertWBO("foo", "bookmarks", new ServerWBO(bookmarkInfo.guid, encryptPayload({
|
||||
id: bookmarkInfo.guid,
|
||||
deleted: true,
|
||||
}), Date.now() / 1000));
|
||||
}), (Date.now() - 60000) / 1000));
|
||||
|
||||
// sync again - we should have a few problems...
|
||||
_("Syncing again.");
|
||||
|
|
|
@ -13,8 +13,6 @@ Cu.import("resource://testing-common/services/sync/utils.js");
|
|||
|
||||
initTestLogging("Trace");
|
||||
Log.repository.getLogger("Sync.Engine.Bookmarks").level = Log.Level.Trace;
|
||||
// sqlite logging generates lots of noise and typically isn't helpful here.
|
||||
Log.repository.getLogger("Sqlite").level = Log.Level.Error;
|
||||
|
||||
// Disable validation so that we don't try to automatically repair the server
|
||||
// when we sync.
|
||||
|
|
|
@ -142,6 +142,7 @@ add_task(async function test_bad_hmac() {
|
|||
deletedCollections = [];
|
||||
deletedItems = [];
|
||||
check_clients_count(1);
|
||||
engine.lastModified = server.getCollection("foo", "clients").timestamp;
|
||||
await engine._sync();
|
||||
|
||||
_("Old record was not deleted, new one uploaded.");
|
||||
|
@ -162,6 +163,7 @@ add_task(async function test_bad_hmac() {
|
|||
await uploadNewKeys();
|
||||
|
||||
// Sync once to upload a record.
|
||||
engine.lastModified = server.getCollection("foo", "clients").timestamp;
|
||||
await engine._sync();
|
||||
check_clients_count(1);
|
||||
|
||||
|
@ -241,6 +243,7 @@ add_task(async function test_full_sync() {
|
|||
|
||||
_("First sync. 2 records downloaded; our record uploaded.");
|
||||
strictEqual(engine.lastRecordUpload, 0);
|
||||
engine.lastModified = server.getCollection("foo", "clients").timestamp;
|
||||
await engine._sync();
|
||||
ok(engine.lastRecordUpload > 0);
|
||||
deepEqual(user.collection("clients").keys().sort(),
|
||||
|
@ -292,6 +295,7 @@ add_task(async function test_sync() {
|
|||
_("First sync. Client record is uploaded.");
|
||||
equal(clientWBO(), undefined);
|
||||
equal(engine.lastRecordUpload, 0);
|
||||
engine.lastModified = server.getCollection("foo", "clients").timestamp;
|
||||
await engine._sync();
|
||||
ok(!!clientWBO().payload);
|
||||
ok(engine.lastRecordUpload > 0);
|
||||
|
@ -300,6 +304,7 @@ add_task(async function test_sync() {
|
|||
engine.lastRecordUpload -= MORE_THAN_CLIENTS_TTL_REFRESH;
|
||||
let lastweek = engine.lastRecordUpload;
|
||||
clientWBO().payload = undefined;
|
||||
engine.lastModified = server.getCollection("foo", "clients").timestamp;
|
||||
await engine._sync();
|
||||
ok(!!clientWBO().payload);
|
||||
ok(engine.lastRecordUpload > lastweek);
|
||||
|
@ -377,6 +382,7 @@ add_task(async function test_last_modified() {
|
|||
let collection = user.collection("clients");
|
||||
|
||||
_("Sync to download the record");
|
||||
engine.lastModified = server.getCollection("foo", "clients").timestamp;
|
||||
await engine._sync();
|
||||
|
||||
equal(engine._store._remoteClients[activeID].serverLastModified, now - 10,
|
||||
|
@ -386,6 +392,8 @@ add_task(async function test_last_modified() {
|
|||
// set a new name to make sure we really did upload.
|
||||
engine._store._remoteClients[activeID].name = "New name";
|
||||
engine._modified.set(activeID, 0);
|
||||
// The sync above also did a POST, so adjust our lastModified.
|
||||
engine.lastModified = server.getCollection("foo", "clients").timestamp;
|
||||
await engine._uploadOutgoing();
|
||||
|
||||
_("Local record should have updated timestamp");
|
||||
|
@ -631,6 +639,7 @@ add_task(async function test_filter_duplicate_names() {
|
|||
|
||||
_("First sync");
|
||||
strictEqual(engine.lastRecordUpload, 0);
|
||||
engine.lastModified = server.getCollection("foo", "clients").timestamp;
|
||||
await engine._sync();
|
||||
ok(engine.lastRecordUpload > 0);
|
||||
deepEqual(user.collection("clients").keys().sort(),
|
||||
|
@ -1023,6 +1032,7 @@ add_task(async function test_merge_commands() {
|
|||
try {
|
||||
_("First sync. 2 records downloaded.");
|
||||
strictEqual(engine.lastRecordUpload, 0);
|
||||
engine.lastModified = server.getCollection("foo", "clients").timestamp;
|
||||
await engine._sync();
|
||||
|
||||
_("Broadcast logout to all clients");
|
||||
|
@ -1075,6 +1085,7 @@ add_task(async function test_duplicate_remote_commands() {
|
|||
try {
|
||||
_("First sync. 1 record downloaded.");
|
||||
strictEqual(engine.lastRecordUpload, 0);
|
||||
engine.lastModified = server.getCollection("foo", "clients").timestamp;
|
||||
await engine._sync();
|
||||
|
||||
_("Send tab to client");
|
||||
|
@ -1093,6 +1104,7 @@ add_task(async function test_duplicate_remote_commands() {
|
|||
|
||||
_("Send another tab to the desktop client");
|
||||
await engine.sendCommand("displayURI", ["https://foobar.com", engine.localID, "Foo bar!"], desktopID);
|
||||
engine.lastModified = server.getCollection("foo", "clients").timestamp;
|
||||
await engine._sync();
|
||||
|
||||
let collection = server.getCollection("foo", "clients");
|
||||
|
@ -1147,6 +1159,7 @@ add_task(async function test_upload_after_reboot() {
|
|||
try {
|
||||
_("First sync. 2 records downloaded.");
|
||||
strictEqual(engine.lastRecordUpload, 0);
|
||||
engine.lastModified = server.getCollection("foo", "clients").timestamp;
|
||||
await engine._sync();
|
||||
|
||||
_("Send tab to client");
|
||||
|
@ -1293,6 +1306,7 @@ add_task(async function test_keep_cleared_commands_after_reboot() {
|
|||
|
||||
commandsProcessed = 0;
|
||||
engine._handleDisplayURIs = (uris) => { commandsProcessed = uris.length };
|
||||
engine.lastModified = server.getCollection("foo", "clients").timestamp;
|
||||
await engine._sync();
|
||||
await engine.processIncomingCommands();
|
||||
equal(commandsProcessed, 1, "We processed one command (the other were cleared)");
|
||||
|
@ -1346,6 +1360,7 @@ add_task(async function test_deleted_commands() {
|
|||
|
||||
try {
|
||||
_("First sync. 2 records downloaded.");
|
||||
engine.lastModified = server.getCollection("foo", "clients").timestamp;
|
||||
await engine._sync();
|
||||
|
||||
_("Delete a record on the server.");
|
||||
|
@ -1354,6 +1369,7 @@ add_task(async function test_deleted_commands() {
|
|||
|
||||
_("Broadcast a command to all clients");
|
||||
await engine.sendCommand("logout", []);
|
||||
engine.lastModified = server.getCollection("foo", "clients").timestamp;
|
||||
await engine._sync();
|
||||
|
||||
deepEqual(collection.keys().sort(), [activeID, engine.localID].sort(),
|
||||
|
@ -1386,6 +1402,7 @@ add_task(async function test_send_uri_ack() {
|
|||
let fakeSenderID = Utils.makeGUID();
|
||||
|
||||
_("Initial sync for empty clients collection");
|
||||
engine.lastModified = server.getCollection("foo", "clients").timestamp;
|
||||
await engine._sync();
|
||||
let collection = server.getCollection("foo", "clients");
|
||||
let ourPayload = JSON.parse(JSON.parse(collection.payload(engine.localID)).ciphertext);
|
||||
|
@ -1400,6 +1417,7 @@ add_task(async function test_send_uri_ack() {
|
|||
server.insertWBO("foo", "clients", new ServerWBO(engine.localID, encryptPayload(ourPayload), now));
|
||||
|
||||
_("Sync again");
|
||||
engine.lastModified = server.getCollection("foo", "clients").timestamp;
|
||||
await engine._sync();
|
||||
compareCommands(engine.localCommands, [{
|
||||
command: "displayURI",
|
||||
|
@ -1463,6 +1481,7 @@ add_task(async function test_command_sync() {
|
|||
|
||||
try {
|
||||
equal(collection.count(), 2, "2 remote records written");
|
||||
engine.lastModified = server.getCollection("foo", "clients").timestamp;
|
||||
await engine._sync();
|
||||
equal(collection.count(), 3, "3 remote records written (+1 for the synced local record)");
|
||||
|
||||
|
@ -1526,6 +1545,7 @@ add_task(async function ensureSameFlowIDs() {
|
|||
protocols: ["1.5"]
|
||||
}), Date.now() / 1000));
|
||||
|
||||
engine.lastModified = server.getCollection("foo", "clients").timestamp;
|
||||
await engine._sync();
|
||||
await engine.sendCommand("wipeAll", []);
|
||||
await engine._sync();
|
||||
|
@ -1660,6 +1680,7 @@ add_task(async function test_other_clients_notified_on_first_sync() {
|
|||
try {
|
||||
engine.lastRecordUpload = 0;
|
||||
_("First sync, should notify other clients");
|
||||
engine.lastModified = server.getCollection("foo", "clients").timestamp;
|
||||
await engine._sync();
|
||||
equal(calls, 1);
|
||||
|
||||
|
|
|
@ -19,8 +19,6 @@ const LoginInfo = Components.Constructor(
|
|||
* read-only.
|
||||
*/
|
||||
|
||||
Log.repository.getLogger("Sqlite").level = Log.Level.Error;
|
||||
|
||||
async function assertChildGuids(folderGuid, expectedChildGuids, message) {
|
||||
let tree = await PlacesUtils.promiseBookmarksTree(folderGuid);
|
||||
let childGuids = tree.children.map(child => child.guid);
|
||||
|
|
|
@ -466,6 +466,7 @@ add_task(async function test_processIncoming_reconcile_locally_deleted_dupe_new(
|
|||
do_check_false((await engine._store.itemExists("DUPE_INCOMING")));
|
||||
do_check_eq("DUPE_LOCAL", (await engine._findDupe({id: "DUPE_INCOMING"})));
|
||||
|
||||
engine.lastModified = server.getCollection(user, engine.name).timestamp;
|
||||
await engine._sync();
|
||||
|
||||
// After the sync, the server's payload for the original ID should be marked
|
||||
|
@ -539,6 +540,7 @@ add_task(async function test_processIncoming_reconcile_changed_dupe() {
|
|||
do_check_true((await engine._store.itemExists("DUPE_LOCAL")));
|
||||
do_check_eq("DUPE_LOCAL", (await engine._findDupe({id: "DUPE_INCOMING"})));
|
||||
|
||||
engine.lastModified = server.getCollection(user, engine.name).timestamp;
|
||||
await engine._sync();
|
||||
|
||||
// The ID should have been changed to incoming.
|
||||
|
@ -577,6 +579,7 @@ add_task(async function test_processIncoming_reconcile_changed_dupe_new() {
|
|||
do_check_true((await engine._store.itemExists("DUPE_LOCAL")));
|
||||
do_check_eq("DUPE_LOCAL", (await engine._findDupe({id: "DUPE_INCOMING"})));
|
||||
|
||||
engine.lastModified = server.getCollection(user, engine.name).timestamp;
|
||||
await engine._sync();
|
||||
|
||||
// The ID should have been changed to incoming.
|
||||
|
|
|
@ -2562,7 +2562,9 @@ extern "C" {
|
|||
pub fn Servo_DeclarationBlock_SerializeOneValue(declarations:
|
||||
RawServoDeclarationBlockBorrowed,
|
||||
property: nsCSSPropertyID,
|
||||
buffer: *mut nsAString);
|
||||
buffer: *mut nsAString,
|
||||
computed_values:
|
||||
ServoStyleContextBorrowedOrNull);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Servo_DeclarationBlock_Count(declarations:
|
||||
|
|
|
@ -518,13 +518,35 @@ impl PropertyDeclarationBlock {
|
|||
}
|
||||
|
||||
/// Take a declaration block known to contain a single property and serialize it.
|
||||
pub fn single_value_to_css<W>(&self, property: &PropertyId, dest: &mut W) -> fmt::Result
|
||||
where W: fmt::Write,
|
||||
pub fn single_value_to_css<W>(
|
||||
&self,
|
||||
property: &PropertyId,
|
||||
dest: &mut W,
|
||||
computed_values: Option<&ComputedValues>,
|
||||
) -> fmt::Result
|
||||
where
|
||||
W: fmt::Write,
|
||||
{
|
||||
match property.as_shorthand() {
|
||||
Err(_longhand_or_custom) => {
|
||||
if self.declarations.len() == 1 {
|
||||
self.declarations[0].0.to_css(dest)
|
||||
let declaration = &self.declarations[0].0;
|
||||
// If we have a longhand declaration with variables, those variables will be
|
||||
// stored as unparsed values. As a temporary measure to produce sensible results
|
||||
// in Gecko's getKeyframes() implementation for CSS animations, if
|
||||
// |computed_values| is supplied, we use it to expand such variable
|
||||
// declarations. This will be fixed properly in Gecko bug 1391537.
|
||||
match (declaration, computed_values) {
|
||||
(&PropertyDeclaration::WithVariables(id, ref unparsed),
|
||||
Some(ref computed_values)) => unparsed
|
||||
.substitute_variables(
|
||||
id,
|
||||
&computed_values.custom_properties(),
|
||||
QuirksMode::NoQuirks,
|
||||
)
|
||||
.to_css(dest),
|
||||
(ref d, _) => d.to_css(dest),
|
||||
}
|
||||
} else {
|
||||
Err(fmt::Error)
|
||||
}
|
||||
|
|
|
@ -564,7 +564,8 @@ pub extern "C" fn Servo_AnimationValue_Serialize(value: RawServoAnimationValueBo
|
|||
let uncomputed_value = AnimationValue::as_arc(&value).uncompute();
|
||||
let mut string = String::new();
|
||||
let rv = PropertyDeclarationBlock::with_one(uncomputed_value, Importance::Normal)
|
||||
.single_value_to_css(&get_property_id_from_nscsspropertyid!(property, ()), &mut string);
|
||||
.single_value_to_css(&get_property_id_from_nscsspropertyid!(property, ()), &mut string,
|
||||
None);
|
||||
debug_assert!(rv.is_ok());
|
||||
|
||||
let buffer = unsafe { buffer.as_mut().unwrap() };
|
||||
|
@ -2142,12 +2143,13 @@ pub extern "C" fn Servo_DeclarationBlock_GetCssText(declarations: RawServoDeclar
|
|||
#[no_mangle]
|
||||
pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue(
|
||||
declarations: RawServoDeclarationBlockBorrowed,
|
||||
property_id: nsCSSPropertyID, buffer: *mut nsAString)
|
||||
property_id: nsCSSPropertyID, buffer: *mut nsAString,
|
||||
computed_values: ServoStyleContextBorrowedOrNull)
|
||||
{
|
||||
let property_id = get_property_id_from_nscsspropertyid!(property_id, ());
|
||||
read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
|
||||
let mut string = String::new();
|
||||
let rv = decls.single_value_to_css(&property_id, &mut string);
|
||||
let rv = decls.single_value_to_css(&property_id, &mut string, computed_values);
|
||||
debug_assert!(rv.is_ok());
|
||||
|
||||
let buffer = unsafe { buffer.as_mut().unwrap() };
|
||||
|
|
|
@ -144,6 +144,21 @@ CreateClientInfo()
|
|||
return c;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsAllowedOnCurrentPlatform(uint32_t aThreatType)
|
||||
{
|
||||
PlatformType platform = GetPlatformType();
|
||||
|
||||
switch (aThreatType) {
|
||||
case POTENTIALLY_HARMFUL_APPLICATION:
|
||||
// Bug 1388582 - Google server would respond 404 error if the request
|
||||
// contains PHA on non-mobile platform.
|
||||
return ANDROID_PLATFORM == platform;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace safebrowsing.
|
||||
} // end of namespace mozilla.
|
||||
|
||||
|
@ -345,6 +360,13 @@ nsUrlClassifierUtils::MakeUpdateRequestV4(const char** aListNames,
|
|||
if (NS_FAILED(rv)) {
|
||||
continue; // Unknown list name.
|
||||
}
|
||||
if (!IsAllowedOnCurrentPlatform(threatType)) {
|
||||
NS_WARNING(nsPrintfCString("Threat type %d (%s) is unsupported on current platform: %d",
|
||||
threatType,
|
||||
aListNames[i],
|
||||
GetPlatformType()).get());
|
||||
continue; // Some threat types are not available on some platforms.
|
||||
}
|
||||
auto lur = r.mutable_list_update_requests()->Add();
|
||||
InitListUpdateRequest(static_cast<ThreatType>(threatType), aStatesBase64[i], lur);
|
||||
}
|
||||
|
@ -378,24 +400,31 @@ nsUrlClassifierUtils::MakeFindFullHashRequestV4(const char** aListNames,
|
|||
|
||||
nsresult rv;
|
||||
|
||||
// Set up FindFullHashesRequest.client_states.
|
||||
for (uint32_t i = 0; i < aListCount; i++) {
|
||||
nsCString stateBinary;
|
||||
rv = Base64Decode(nsDependentCString(aListStatesBase64[i]), stateBinary);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
r.add_client_states(stateBinary.get(), stateBinary.Length());
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Set up FindFullHashesRequest.threat_info.
|
||||
auto threatInfo = r.mutable_threat_info();
|
||||
|
||||
// 1) Set threat types.
|
||||
for (uint32_t i = 0; i < aListCount; i++) {
|
||||
// Add threat types.
|
||||
uint32_t threatType;
|
||||
rv = ConvertListNameToThreatType(nsDependentCString(aListNames[i]), &threatType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!IsAllowedOnCurrentPlatform(threatType)) {
|
||||
NS_WARNING(nsPrintfCString("Threat type %d (%s) is unsupported on current platform: %d",
|
||||
threatType,
|
||||
aListNames[i],
|
||||
GetPlatformType()).get());
|
||||
continue;
|
||||
}
|
||||
threatInfo->add_threat_types((ThreatType)threatType);
|
||||
|
||||
// Add client states for index 'i' only when the threat type is available
|
||||
// on current platform.
|
||||
nsCString stateBinary;
|
||||
rv = Base64Decode(nsDependentCString(aListStatesBase64[i]), stateBinary);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
r.add_client_states(stateBinary.get(), stateBinary.Length());
|
||||
}
|
||||
|
||||
// 2) Set platform type.
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||
|
||||
let urlUtils = Cc["@mozilla.org/url-classifier/utils;1"]
|
||||
.getService(Ci.nsIUrlClassifierUtils);
|
||||
|
||||
function testUpdateRequest() {
|
||||
let requestWithPHA =
|
||||
urlUtils.makeUpdateRequestV4(["goog-phish-proto", "goog-harmful-proto"],
|
||||
["AAAAAA", "AAAAAA"], 2);
|
||||
|
||||
let requestNoPHA =
|
||||
urlUtils.makeUpdateRequestV4(["goog-phish-proto"], ["AAAAAA"], 1);
|
||||
|
||||
if (AppConstants.platform === "android") {
|
||||
notEqual(requestWithPHA, requestNoPHA,
|
||||
"PHA (i.e. goog-harmful-proto) shouldn't be filtered on mobile platform.");
|
||||
} else {
|
||||
equal(requestWithPHA, requestNoPHA,
|
||||
"PHA (i.e. goog-harmful-proto) should be filtered on non-mobile platform.");
|
||||
}
|
||||
}
|
||||
|
||||
function testFullHashRequest() {
|
||||
let requestWithPHA =
|
||||
urlUtils.makeFindFullHashRequestV4(["goog-phish-proto", "goog-harmful-proto"],
|
||||
["", ""], // state.
|
||||
[btoa("0123")], // prefix.
|
||||
2, 1);
|
||||
|
||||
let requestNoPHA =
|
||||
urlUtils.makeFindFullHashRequestV4(["goog-phish-proto"],
|
||||
[""], // state.
|
||||
[btoa("0123")], // prefix.
|
||||
1, 1);
|
||||
|
||||
if (AppConstants.platform === "android") {
|
||||
notEqual(requestWithPHA, requestNoPHA,
|
||||
"PHA (i.e. goog-harmful-proto) shouldn't be filtered on mobile platform.");
|
||||
} else {
|
||||
equal(requestWithPHA, requestNoPHA,
|
||||
"PHA (i.e. goog-harmful-proto) should be filtered on non-mobile platform.");
|
||||
}
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
testUpdateRequest();
|
||||
testFullHashRequest();
|
||||
}
|
|
@ -22,3 +22,4 @@ support-files =
|
|||
[test_listmanager.js]
|
||||
[test_pref.js]
|
||||
[test_safebrowsing_protobuf.js]
|
||||
[test_bug1388582_pha_mobile_only.js]
|
|
@ -111,22 +111,8 @@ endif
|
|||
# may be overridden if necessary.
|
||||
MOZDEPTH ?= $(DEPTH)
|
||||
|
||||
ifdef MOZ_MAKE_COMPLETE_MAR
|
||||
MAKE_COMPLETE_MAR = 1
|
||||
ifeq ($(OS_ARCH), WINNT)
|
||||
ifneq ($(MOZ_PKG_FORMAT), SFX7Z)
|
||||
MAKE_COMPLETE_MAR =
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
repackage-zip: UNPACKAGE='$(ZIP_IN)'
|
||||
repackage-zip: libs-$(AB_CD)
|
||||
# call a hook for apps to put their uninstall helper.exe into the package
|
||||
$(UNINSTALLER_PACKAGE_HOOK)
|
||||
# call a hook for apps to build the stub installer
|
||||
ifdef MOZ_STUB_INSTALLER
|
||||
$(STUB_HOOK)
|
||||
endif
|
||||
repackage-zip:
|
||||
$(PYTHON) $(MOZILLA_DIR)/toolkit/mozapps/installer/l10n-repack.py $(STAGEDIST) $(DIST)/xpi-stage/locale-$(AB_CD) \
|
||||
$(MOZ_PKG_EXTRAL10N) \
|
||||
$(if $(filter omni,$(MOZ_PACKAGER_FORMAT)),$(if $(NON_OMNIJAR_FILES),--non-resource $(NON_OMNIJAR_FILES)))
|
||||
|
@ -146,9 +132,9 @@ endif
|
|||
endif
|
||||
|
||||
$(NSINSTALL) -D $(DIST)/l10n-stage/$(PKG_PATH)
|
||||
cd $(DIST)/l10n-stage; \
|
||||
$(MAKE_PACKAGE)
|
||||
ifdef MAKE_COMPLETE_MAR
|
||||
(cd $(DIST)/l10n-stage; \
|
||||
$(MAKE_PACKAGE))
|
||||
ifdef MOZ_MAKE_COMPLETE_MAR
|
||||
$(MAKE) -C $(MOZDEPTH)/tools/update-packaging full-update AB_CD=$(AB_CD) \
|
||||
PACKAGE_BASE_DIR='$(ABS_DIST)/l10n-stage'
|
||||
endif
|
||||
|
@ -207,13 +193,18 @@ endif
|
|||
$(RM) -rf $(REAL_LOCALE_MERGEDIR)
|
||||
$(MOZILLA_DIR)/mach compare-locales --l10n-base $(L10NBASEDIR) --merge-dir $(REAL_LOCALE_MERGEDIR) $*
|
||||
|
||||
langpack-%: LANGPACK_FILE=$(ABS_DIST)/$(PKG_LANGPACK_PATH)$(PKG_LANGPACK_BASENAME).xpi
|
||||
langpack-%: AB_CD=$*
|
||||
langpack-%: XPI_NAME=locale-$*
|
||||
langpack-%: IS_LANGUAGE_REPACK=1
|
||||
langpack-%: IS_LANGPACK=1
|
||||
langpack-%: libs-%
|
||||
langpack-%: AB_CD=$*
|
||||
langpack-%:
|
||||
@echo 'Making langpack $(LANGPACK_FILE)'
|
||||
@$(MAKE) libs-$(AB_CD)
|
||||
@$(MAKE) package-langpack-$(AB_CD)
|
||||
|
||||
package-langpack-%: LANGPACK_FILE=$(ABS_DIST)/$(PKG_LANGPACK_PATH)$(PKG_LANGPACK_BASENAME).xpi
|
||||
package-langpack-%: XPI_NAME=locale-$*
|
||||
package-langpack-%: AB_CD=$*
|
||||
package-langpack-%:
|
||||
$(NSINSTALL) -D $(DIST)/$(PKG_LANGPACK_PATH)
|
||||
$(call py_action,preprocessor,$(DEFINES) $(ACDEFINES) \
|
||||
-DTK_DEFINES=$(TK_DEFINES) -DAPP_DEFINES=$(APP_DEFINES) $(MOZILLA_DIR)/toolkit/locales/generic/install.rdf -o $(DIST)/xpi-stage/$(XPI_NAME)/install.rdf)
|
||||
|
|
|
@ -152,10 +152,6 @@ button.warning {
|
|||
padding-top: 0;
|
||||
}
|
||||
|
||||
.category[selected="true"]:hover {
|
||||
color: #0060df;
|
||||
}
|
||||
|
||||
.category[disabled] {
|
||||
overflow: hidden;
|
||||
height: 0;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
--in-content-category-border-focus: 1px dotted #0a84ff;
|
||||
--in-content-category-text: #0c0c0d;
|
||||
--in-content-category-text-selected: #0a84ff;
|
||||
--in-content-category-hover: rgba(12,12,13,0.1);
|
||||
--in-content-tab-color: #424f5a;
|
||||
--in-content-link-color: #0a84ff;
|
||||
--in-content-link-color-hover: #0060df;
|
||||
|
@ -339,6 +340,7 @@ html|*.help-button:hover {
|
|||
fill: white;
|
||||
stroke: #808080;
|
||||
stroke-opacity: 1;
|
||||
background-color: var(--in-content-category-hover);
|
||||
}
|
||||
|
||||
html|*.help-button:hover:active {
|
||||
|
@ -640,18 +642,23 @@ xul|*.radio-label-box {
|
|||
padding-top: 70px;
|
||||
margin: 0;
|
||||
border-width: 0;
|
||||
width: 240px;
|
||||
}
|
||||
|
||||
*|*.category {
|
||||
width: 240px;
|
||||
min-height: 48px;
|
||||
-moz-appearance: none;
|
||||
color: var(--in-content-category-text);
|
||||
padding-inline-start: 44px;
|
||||
margin-inline-start: 34px;
|
||||
padding-inline-end: 10px;
|
||||
padding-inline-start: 10px;
|
||||
transition: background-color 150ms;
|
||||
}
|
||||
|
||||
*|*.category:hover {
|
||||
background-color: var(--in-content-category-hover);
|
||||
}
|
||||
|
||||
*|*.category[selected],
|
||||
*|*.category.selected {
|
||||
color: var(--in-content-category-text-selected);
|
||||
|
@ -684,7 +691,7 @@ xul|*.radio-label-box {
|
|||
fill-opacity: 1;
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
@media (max-width: 830px) {
|
||||
#categories {
|
||||
width: 118px;
|
||||
}
|
||||
|
@ -693,8 +700,26 @@ xul|*.radio-label-box {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.category {
|
||||
padding-inline-start: 13px; /* make category icons align center */
|
||||
margin-inline-end: 40px;
|
||||
}
|
||||
|
||||
.help-button {
|
||||
font-size: 0 !important;
|
||||
margin-inline-start: 41px !important; /* make the question mark icon align center */
|
||||
background-position: 10px !important;
|
||||
padding-inline-start: 0px !important;
|
||||
width: 36px !important;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.pane-container {
|
||||
margin-inline-end: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,9 @@ class WidgetRenderingContext;
|
|||
// has been present in the same form since at least OS X 10.2.8.
|
||||
- (EventRef)_eventRef;
|
||||
|
||||
// stage From 10.10.3 for force touch event
|
||||
@property (readonly) NSInteger stage;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSView (Undocumented)
|
||||
|
@ -204,6 +207,9 @@ class WidgetRenderingContext;
|
|||
// The mask image that's used when painting into the titlebar using basic
|
||||
// CGContext painting (i.e. non-accelerated).
|
||||
CGImageRef mTopLeftCornerMask;
|
||||
|
||||
// Last pressure stage by trackpad's force click
|
||||
NSInteger mLastPressureStage;
|
||||
}
|
||||
|
||||
// class initialization
|
||||
|
|
|
@ -3343,6 +3343,7 @@ NSEvent* gLastDragMouseDownEvent = nil;
|
|||
#endif
|
||||
|
||||
mTopLeftCornerMask = NULL;
|
||||
mLastPressureStage = 0;
|
||||
}
|
||||
|
||||
// register for things we'll take from other applications
|
||||
|
@ -6391,6 +6392,24 @@ provideDataForType:(NSString*)aType
|
|||
return command.mSucceeded && command.mIsEnabled;
|
||||
}
|
||||
|
||||
- (void)pressureChangeWithEvent:(NSEvent*)event
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK
|
||||
|
||||
NSInteger stage = [event stage];
|
||||
if (mLastPressureStage == 1 && stage == 2) {
|
||||
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
|
||||
if ([userDefaults integerForKey:@"com.apple.trackpad.forceClick"] == 1) {
|
||||
// This is no public API to get configuration for current force click.
|
||||
// This is filed as radar 29294285.
|
||||
[self quickLookWithEvent:event];
|
||||
}
|
||||
}
|
||||
mLastPressureStage = stage;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsChildView::GetSelectionAsPlaintext(nsAString& aResult)
|
||||
{
|
||||
|
|
|
@ -793,7 +793,8 @@ nsWindow::Create(nsIWidget* aParent,
|
|||
}
|
||||
|
||||
if (!IsWin8OrLater() &&
|
||||
HasBogusPopupsDropShadowOnMultiMonitor()) {
|
||||
HasBogusPopupsDropShadowOnMultiMonitor() &&
|
||||
ShouldUseOffMainThreadCompositing()) {
|
||||
extendedStyle |= WS_EX_COMPOSITED;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче