merge mozilla-central to mozilla-inbound. r=merge a=merge

This commit is contained in:
Sebastian Hengst 2017-08-21 13:43:53 +02:00
Родитель 4ea589bff9 cf6a9260e7
Коммит 02a34cdd40
71 изменённых файлов: 957 добавлений и 579 удалений

Просмотреть файл

@ -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

Двоичные данные
dom/media/test/bipbop-cenc-video-10s.mp4 Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -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;
}