mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
3a42c363cc
2
CLOBBER
2
CLOBBER
@ -22,4 +22,4 @@
|
||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 1276696 - New Android dependencies
|
||||
Bug 1267887 - Build skew after updating rust mp4parse
|
||||
|
@ -611,7 +611,6 @@ if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
|
||||
|
||||
|
||||
var DOMFullscreenHandler = {
|
||||
_fullscreenDoc: null,
|
||||
|
||||
init: function() {
|
||||
addMessageListener("DOMFullscreen:Entered", this);
|
||||
@ -646,11 +645,14 @@ var DOMFullscreenHandler = {
|
||||
break;
|
||||
}
|
||||
case "DOMFullscreen:CleanUp": {
|
||||
if (windowUtils) {
|
||||
// If we've exited fullscreen at this point, no need to record
|
||||
// transaction id or call exit fullscreen. This is especially
|
||||
// important for non-e10s, since in that case, it is possible
|
||||
// that no more paint would be triggered after this point.
|
||||
if (content.document.fullscreenElement && windowUtils) {
|
||||
this._lastTransactionId = windowUtils.lastTransactionId;
|
||||
windowUtils.exitFullscreen();
|
||||
}
|
||||
this._fullscreenDoc = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -663,9 +665,8 @@ var DOMFullscreenHandler = {
|
||||
break;
|
||||
}
|
||||
case "MozDOMFullscreen:NewOrigin": {
|
||||
this._fullscreenDoc = aEvent.target;
|
||||
sendAsyncMessage("DOMFullscreen:NewOrigin", {
|
||||
originNoSuffix: this._fullscreenDoc.nodePrincipal.originNoSuffix,
|
||||
originNoSuffix: aEvent.target.nodePrincipal.originNoSuffix,
|
||||
});
|
||||
break;
|
||||
}
|
||||
@ -687,7 +688,10 @@ var DOMFullscreenHandler = {
|
||||
case "MozAfterPaint": {
|
||||
// Only send Painted signal after we actually finish painting
|
||||
// the transition for the fullscreen change.
|
||||
if (aEvent.transactionId > this._lastTransactionId) {
|
||||
// Note that this._lastTransactionId is not set when in non-e10s
|
||||
// mode, so we need to check that explicitly.
|
||||
if (!this._lastTransactionId ||
|
||||
aEvent.transactionId > this._lastTransactionId) {
|
||||
removeEventListener("MozAfterPaint", this);
|
||||
sendAsyncMessage("DOMFullscreen:Painted");
|
||||
}
|
||||
|
@ -53,6 +53,8 @@ PluginContent.prototype = {
|
||||
global.addMessageListener("BrowserPlugins:NPAPIPluginProcessCrashed", this);
|
||||
global.addMessageListener("BrowserPlugins:CrashReportSubmitted", this);
|
||||
global.addMessageListener("BrowserPlugins:Test:ClearCrashData", this);
|
||||
|
||||
Services.obs.addObserver(this, "Plugin::HiddenPluginTouched", false);
|
||||
},
|
||||
|
||||
uninit: function() {
|
||||
@ -75,6 +77,8 @@ PluginContent.prototype = {
|
||||
global.removeMessageListener("BrowserPlugins:Test:ClearCrashData", this);
|
||||
delete this.global;
|
||||
delete this.content;
|
||||
|
||||
Services.obs.removeObserver(this, "Plugin::HiddenPluginTouched");
|
||||
},
|
||||
|
||||
receiveMessage: function (msg) {
|
||||
@ -116,6 +120,15 @@ PluginContent.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
observe: function observe(aSubject, aTopic, aData) {
|
||||
let pluginTag = aSubject.QueryInterface(Ci.nsIPluginTag);
|
||||
if (aTopic == "Plugin::HiddenPluginTouched") {
|
||||
this._showClickToPlayNotification(pluginTag, false);
|
||||
} else {
|
||||
Cu.reportError("unknown topic observed: " + aTopic);
|
||||
}
|
||||
},
|
||||
|
||||
onPageShow: function (event) {
|
||||
// Ignore events that aren't from the main document.
|
||||
if (!this.content || event.target != this.content.document) {
|
||||
@ -194,6 +207,45 @@ PluginContent.prototype = {
|
||||
};
|
||||
},
|
||||
|
||||
_getPluginInfoForTag: function (pluginTag, tagMimetype) {
|
||||
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
||||
|
||||
let pluginName = gNavigatorBundle.GetStringFromName("pluginInfo.unknownPlugin");
|
||||
let permissionString = null;
|
||||
let blocklistState = null;
|
||||
|
||||
if (pluginTag) {
|
||||
pluginName = BrowserUtils.makeNicePluginName(pluginTag.name);
|
||||
|
||||
permissionString = pluginHost.getPermissionStringForTag(pluginTag);
|
||||
blocklistState = pluginTag.blocklistState;
|
||||
|
||||
// Convert this from nsIPluginTag so it can be serialized.
|
||||
let properties = ["name", "description", "filename", "version", "enabledState", "niceName"];
|
||||
let pluginTagCopy = {};
|
||||
for (let prop of properties) {
|
||||
pluginTagCopy[prop] = pluginTag[prop];
|
||||
}
|
||||
pluginTag = pluginTagCopy;
|
||||
|
||||
// Make state-softblocked == state-notblocked for our purposes,
|
||||
// they have the same UI. STATE_OUTDATED should not exist for plugin
|
||||
// items, but let's alias it anyway, just in case.
|
||||
if (blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED ||
|
||||
blocklistState == Ci.nsIBlocklistService.STATE_OUTDATED) {
|
||||
blocklistState = Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
return { mimetype: tagMimetype,
|
||||
pluginName: pluginName,
|
||||
pluginTag: pluginTag,
|
||||
permissionString: permissionString,
|
||||
fallbackType: null,
|
||||
blocklistState: blocklistState,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the visibility of the plugin overlay.
|
||||
*/
|
||||
@ -710,7 +762,13 @@ PluginContent.prototype = {
|
||||
let location = this.content.document.location.href;
|
||||
|
||||
for (let p of plugins) {
|
||||
let pluginInfo = this._getPluginInfo(p);
|
||||
let pluginInfo;
|
||||
if (p instanceof Ci.nsIPluginTag) {
|
||||
let mimeType = p.getMimeTypes() > 0 ? p.getMimeTypes()[0] : null;
|
||||
pluginInfo = this._getPluginInfoForTag(p, mimeType);
|
||||
} else {
|
||||
pluginInfo = this._getPluginInfo(p);
|
||||
}
|
||||
if (pluginInfo.permissionString === null) {
|
||||
Cu.reportError("No permission string for active plugin.");
|
||||
continue;
|
||||
|
@ -27,6 +27,7 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
|
||||
private final Member[] mObjects;
|
||||
private AnnotatableEntity mNextReturnValue;
|
||||
private int mElementIndex;
|
||||
private AnnotationInfo mClassInfo;
|
||||
|
||||
private boolean mIterateEveryEntry;
|
||||
|
||||
@ -55,8 +56,8 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
|
||||
|
||||
// Check for "Wrap ALL the things" flag.
|
||||
for (Annotation annotation : aClass.getDeclaredAnnotations()) {
|
||||
final String annotationTypeName = annotation.annotationType().getName();
|
||||
if (annotationTypeName.equals("org.mozilla.gecko.annotation.WrapForJNI")) {
|
||||
mClassInfo = buildAnnotationInfo(aClass, annotation);
|
||||
if (mClassInfo != null) {
|
||||
mIterateEveryEntry = true;
|
||||
break;
|
||||
}
|
||||
@ -115,6 +116,73 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
|
||||
return ret;
|
||||
}
|
||||
|
||||
private AnnotationInfo buildAnnotationInfo(AnnotatedElement element, Annotation annotation) {
|
||||
Class<? extends Annotation> annotationType = annotation.annotationType();
|
||||
final String annotationTypeName = annotationType.getName();
|
||||
if (!annotationTypeName.equals("org.mozilla.gecko.annotation.WrapForJNI")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String stubName = null;
|
||||
boolean isMultithreadedStub = false;
|
||||
boolean noThrow = false;
|
||||
boolean narrowChars = false;
|
||||
boolean catchException = false;
|
||||
try {
|
||||
// Determine the explicitly-given name of the stub to generate, if any.
|
||||
final Method stubNameMethod = annotationType.getDeclaredMethod("stubName");
|
||||
stubNameMethod.setAccessible(true);
|
||||
stubName = (String) stubNameMethod.invoke(annotation);
|
||||
|
||||
if (element instanceof Class<?>) {
|
||||
// Make @WrapForJNI always allow multithread by default, individual methods can then
|
||||
// override with their own annotation
|
||||
isMultithreadedStub = true;
|
||||
} else {
|
||||
// Determine if the generated stub is to allow calls from multiple threads.
|
||||
final Method multithreadedStubMethod = annotationType.getDeclaredMethod("allowMultithread");
|
||||
multithreadedStubMethod.setAccessible(true);
|
||||
isMultithreadedStub = (Boolean) multithreadedStubMethod.invoke(annotation);
|
||||
}
|
||||
|
||||
// Determine if ignoring exceptions
|
||||
final Method noThrowMethod = annotationType.getDeclaredMethod("noThrow");
|
||||
noThrowMethod.setAccessible(true);
|
||||
noThrow = (Boolean) noThrowMethod.invoke(annotation);
|
||||
|
||||
// Determine if strings should be wide or narrow
|
||||
final Method narrowCharsMethod = annotationType.getDeclaredMethod("narrowChars");
|
||||
narrowCharsMethod.setAccessible(true);
|
||||
narrowChars = (Boolean) narrowCharsMethod.invoke(annotation);
|
||||
|
||||
// Determine if we should catch exceptions
|
||||
final Method catchExceptionMethod = annotationType.getDeclaredMethod("catchException");
|
||||
catchExceptionMethod.setAccessible(true);
|
||||
catchException = (Boolean) catchExceptionMethod.invoke(annotation);
|
||||
|
||||
} catch (NoSuchMethodException e) {
|
||||
System.err.println("Unable to find expected field on WrapForJNI annotation. Did the signature change?");
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(3);
|
||||
} catch (IllegalAccessException e) {
|
||||
System.err.println("IllegalAccessException reading fields on WrapForJNI annotation. Seems the semantics of Reflection have changed...");
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(4);
|
||||
} catch (InvocationTargetException e) {
|
||||
System.err.println("InvocationTargetException reading fields on WrapForJNI annotation. This really shouldn't happen.");
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(5);
|
||||
}
|
||||
|
||||
// If the method name was not explicitly given in the annotation generate one...
|
||||
if (stubName.isEmpty()) {
|
||||
stubName = Utils.getNativeName(element);
|
||||
}
|
||||
|
||||
return new AnnotationInfo(
|
||||
stubName, isMultithreadedStub, noThrow, narrowChars, catchException);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and cache the next appropriately annotated method, plus the annotation parameter, if
|
||||
* one exists. Otherwise cache null, so hasNext returns false.
|
||||
@ -124,63 +192,9 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
|
||||
Member candidateElement = mObjects[mElementIndex];
|
||||
mElementIndex++;
|
||||
for (Annotation annotation : ((AnnotatedElement) candidateElement).getDeclaredAnnotations()) {
|
||||
// WrappedJNIMethod has parameters. Use Reflection to obtain them.
|
||||
Class<? extends Annotation> annotationType = annotation.annotationType();
|
||||
final String annotationTypeName = annotationType.getName();
|
||||
if (annotationTypeName.equals("org.mozilla.gecko.annotation.WrapForJNI")) {
|
||||
String stubName = null;
|
||||
boolean isMultithreadedStub = false;
|
||||
boolean noThrow = false;
|
||||
boolean narrowChars = false;
|
||||
boolean catchException = false;
|
||||
try {
|
||||
// Determine the explicitly-given name of the stub to generate, if any.
|
||||
final Method stubNameMethod = annotationType.getDeclaredMethod("stubName");
|
||||
stubNameMethod.setAccessible(true);
|
||||
stubName = (String) stubNameMethod.invoke(annotation);
|
||||
|
||||
// Determine if the generated stub is to allow calls from multiple threads.
|
||||
final Method multithreadedStubMethod = annotationType.getDeclaredMethod("allowMultithread");
|
||||
multithreadedStubMethod.setAccessible(true);
|
||||
isMultithreadedStub = (Boolean) multithreadedStubMethod.invoke(annotation);
|
||||
|
||||
// Determine if ignoring exceptions
|
||||
final Method noThrowMethod = annotationType.getDeclaredMethod("noThrow");
|
||||
noThrowMethod.setAccessible(true);
|
||||
noThrow = (Boolean) noThrowMethod.invoke(annotation);
|
||||
|
||||
// Determine if strings should be wide or narrow
|
||||
final Method narrowCharsMethod = annotationType.getDeclaredMethod("narrowChars");
|
||||
narrowCharsMethod.setAccessible(true);
|
||||
narrowChars = (Boolean) narrowCharsMethod.invoke(annotation);
|
||||
|
||||
// Determine if we should catch exceptions
|
||||
final Method catchExceptionMethod = annotationType.getDeclaredMethod("catchException");
|
||||
catchExceptionMethod.setAccessible(true);
|
||||
catchException = (Boolean) catchExceptionMethod.invoke(annotation);
|
||||
|
||||
} catch (NoSuchMethodException e) {
|
||||
System.err.println("Unable to find expected field on WrapForJNI annotation. Did the signature change?");
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(3);
|
||||
} catch (IllegalAccessException e) {
|
||||
System.err.println("IllegalAccessException reading fields on WrapForJNI annotation. Seems the semantics of Reflection have changed...");
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(4);
|
||||
} catch (InvocationTargetException e) {
|
||||
System.err.println("InvocationTargetException reading fields on WrapForJNI annotation. This really shouldn't happen.");
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(5);
|
||||
}
|
||||
|
||||
// If the method name was not explicitly given in the annotation generate one...
|
||||
if (stubName.isEmpty()) {
|
||||
stubName = Utils.getNativeName(candidateElement);
|
||||
}
|
||||
|
||||
AnnotationInfo annotationInfo = new AnnotationInfo(
|
||||
stubName, isMultithreadedStub, noThrow, narrowChars, catchException);
|
||||
mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
|
||||
AnnotationInfo info = buildAnnotationInfo((AnnotatedElement)candidateElement, annotation);
|
||||
if (info != null) {
|
||||
mNextReturnValue = new AnnotatableEntity(candidateElement, info);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -190,10 +204,10 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
|
||||
if (mIterateEveryEntry) {
|
||||
AnnotationInfo annotationInfo = new AnnotationInfo(
|
||||
Utils.getNativeName(candidateElement),
|
||||
/* multithreaded */ true,
|
||||
/* noThrow */ false,
|
||||
/* narrowChars */ false,
|
||||
/* catchException */ false);
|
||||
mClassInfo.isMultithreaded,
|
||||
mClassInfo.noThrow,
|
||||
mClassInfo.narrowChars,
|
||||
mClassInfo.catchException);
|
||||
mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
|
||||
return;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ package org.mozilla.gecko.annotationProcessors.utils;
|
||||
|
||||
import org.mozilla.gecko.annotationProcessors.AnnotationInfo;
|
||||
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
@ -212,6 +213,33 @@ public class Utils {
|
||||
return name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the C++ name for a member.
|
||||
*
|
||||
* @param member Member to get the name for.
|
||||
* @return JNI name as a string
|
||||
*/
|
||||
public static String getNativeName(Class<?> clz) {
|
||||
final String name = clz.getName();
|
||||
return name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the C++ name for a member.
|
||||
*
|
||||
* @param member Member to get the name for.
|
||||
* @return JNI name as a string
|
||||
*/
|
||||
public static String getNativeName(AnnotatedElement element) {
|
||||
if (element instanceof Class<?>) {
|
||||
return getNativeName((Class<?>)element);
|
||||
} else if (element instanceof Member) {
|
||||
return getNativeName((Member)element);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JNI name for a member.
|
||||
*
|
||||
|
@ -86,6 +86,7 @@
|
||||
#include "nsWhitespaceTokenizer.h"
|
||||
#include "nsICookieService.h"
|
||||
#include "nsIConsoleReportCollector.h"
|
||||
#include "nsObjectLoadingContent.h"
|
||||
|
||||
// we want to explore making the document own the load group
|
||||
// so we can associate the document URI with the load group.
|
||||
@ -2524,15 +2525,35 @@ nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed)
|
||||
if (frameElement && !frameElement->IsXULElement()) {
|
||||
// We do not allow document inside any containing element other
|
||||
// than iframe to enter fullscreen.
|
||||
if (!frameElement->IsHTMLElement(nsGkAtoms::iframe)) {
|
||||
return NS_OK;
|
||||
}
|
||||
// If any ancestor iframe does not have allowfullscreen attribute
|
||||
// set, then fullscreen is not allowed.
|
||||
if (!frameElement->HasAttr(kNameSpaceID_None,
|
||||
nsGkAtoms::allowfullscreen) &&
|
||||
!frameElement->HasAttr(kNameSpaceID_None,
|
||||
nsGkAtoms::mozallowfullscreen)) {
|
||||
if (frameElement->IsHTMLElement(nsGkAtoms::iframe)) {
|
||||
// If any ancestor iframe does not have allowfullscreen attribute
|
||||
// set, then fullscreen is not allowed.
|
||||
if (!frameElement->HasAttr(kNameSpaceID_None,
|
||||
nsGkAtoms::allowfullscreen) &&
|
||||
!frameElement->HasAttr(kNameSpaceID_None,
|
||||
nsGkAtoms::mozallowfullscreen)) {
|
||||
return NS_OK;
|
||||
}
|
||||
} else if (frameElement->IsHTMLElement(nsGkAtoms::embed)) {
|
||||
// Respect allowfullscreen only if this is a rewritten YouTube embed.
|
||||
nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent =
|
||||
do_QueryInterface(frameElement);
|
||||
if (!objectLoadingContent) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsObjectLoadingContent* olc =
|
||||
static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
|
||||
if (!olc->IsRewrittenYoutubeEmbed()) {
|
||||
return NS_OK;
|
||||
}
|
||||
// We don't have to check prefixed attributes because Flash does not
|
||||
// support them.
|
||||
if (!frameElement->HasAttr(kNameSpaceID_None,
|
||||
nsGkAtoms::allowfullscreen)) {
|
||||
return NS_OK;
|
||||
}
|
||||
} else {
|
||||
// neither iframe nor embed
|
||||
return NS_OK;
|
||||
}
|
||||
nsIDocument* doc = frameElement->GetUncomposedDoc();
|
||||
|
@ -1733,18 +1733,17 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
if (HasPointerLock()) {
|
||||
nsIDocument::UnlockPointer();
|
||||
}
|
||||
if (mState.HasState(NS_EVENT_STATE_FULL_SCREEN)) {
|
||||
// The element being removed is an ancestor of the full-screen element,
|
||||
// exit full-screen state.
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
||||
NS_LITERAL_CSTRING("DOM"), OwnerDoc(),
|
||||
nsContentUtils::eDOM_PROPERTIES,
|
||||
"RemovedFullscreenElement");
|
||||
// Fully exit full-screen.
|
||||
nsIDocument::ExitFullscreenInDocTree(OwnerDoc());
|
||||
}
|
||||
if (aNullParent) {
|
||||
if (IsFullScreenAncestor()) {
|
||||
// The element being removed is an ancestor of the full-screen element,
|
||||
// exit full-screen state.
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
||||
NS_LITERAL_CSTRING("DOM"), OwnerDoc(),
|
||||
nsContentUtils::eDOM_PROPERTIES,
|
||||
"RemovedFullscreenElement");
|
||||
// Fully exit full-screen.
|
||||
nsIDocument::ExitFullscreenInDocTree(OwnerDoc());
|
||||
}
|
||||
|
||||
if (GetParent() && GetParent()->IsInUncomposedDoc()) {
|
||||
// Update the editable descendant count in the ancestors before we
|
||||
// lose the reference to the parent.
|
||||
|
@ -192,15 +192,6 @@ public:
|
||||
*/
|
||||
void UpdateLinkState(EventStates aState);
|
||||
|
||||
/**
|
||||
* Returns true if this element is either a full-screen element or an
|
||||
* ancestor of the full-screen element.
|
||||
*/
|
||||
bool IsFullScreenAncestor() const {
|
||||
return mState.HasAtLeastOneOfStates(NS_EVENT_STATE_FULL_SCREEN_ANCESTOR |
|
||||
NS_EVENT_STATE_FULL_SCREEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* The style state of this element. This is the real state of the element
|
||||
* with any style locks applied for pseudo-class inspecting.
|
||||
|
@ -1846,6 +1846,12 @@ WebSocketImpl::InitializeConnection(nsIPrincipal* aPrincipal)
|
||||
// are not thread-safe.
|
||||
mOriginDocument = nullptr;
|
||||
|
||||
|
||||
// The TriggeringPrincipal for websockets must always be a script.
|
||||
// Let's make sure that the doc's principal (if a doc exists)
|
||||
// and aPrincipal are same origin.
|
||||
MOZ_ASSERT(!doc || doc->NodePrincipal()->Equals(aPrincipal));
|
||||
|
||||
wsChannel->InitLoadInfo(doc ? doc->AsDOMNode() : nullptr,
|
||||
doc ? doc->NodePrincipal() : aPrincipal,
|
||||
aPrincipal,
|
||||
|
@ -1344,6 +1344,80 @@ nsContentUtils::GetParserService()
|
||||
return sParserService;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function that parses a sandbox attribute (of an <iframe> or a CSP
|
||||
* directive) and converts it to the set of flags used internally.
|
||||
*
|
||||
* @param aSandboxAttr the sandbox attribute
|
||||
* @return the set of flags (SANDBOXED_NONE if aSandboxAttr is
|
||||
* null)
|
||||
*/
|
||||
uint32_t
|
||||
nsContentUtils::ParseSandboxAttributeToFlags(const nsAttrValue* aSandboxAttr)
|
||||
{
|
||||
if (!aSandboxAttr) {
|
||||
return SANDBOXED_NONE;
|
||||
}
|
||||
|
||||
uint32_t out = SANDBOX_ALL_FLAGS;
|
||||
|
||||
#define SANDBOX_KEYWORD(string, atom, flags) \
|
||||
if (aSandboxAttr->Contains(nsGkAtoms::atom, eIgnoreCase)) { \
|
||||
out &= ~(flags); \
|
||||
}
|
||||
#include "IframeSandboxKeywordList.h"
|
||||
#undef SANDBOX_KEYWORD
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function that checks if a string matches a valid sandbox flag.
|
||||
*
|
||||
* @param aFlag the potential sandbox flag.
|
||||
* @return true if the flag is a sandbox flag.
|
||||
*/
|
||||
bool
|
||||
nsContentUtils::IsValidSandboxFlag(const nsAString& aFlag)
|
||||
{
|
||||
#define SANDBOX_KEYWORD(string, atom, flags) \
|
||||
if (EqualsIgnoreASCIICase(nsDependentAtomString(nsGkAtoms::atom), aFlag)) { \
|
||||
return true; \
|
||||
}
|
||||
#include "IframeSandboxKeywordList.h"
|
||||
#undef SANDBOX_KEYWORD
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function that returns a string attribute corresponding to the
|
||||
* sandbox flags.
|
||||
*
|
||||
* @param aFlags the sandbox flags
|
||||
* @param aString the attribute corresponding to the flags (null if aFlags
|
||||
* is zero)
|
||||
*/
|
||||
void
|
||||
nsContentUtils::SandboxFlagsToString(uint32_t aFlags, nsAString& aString)
|
||||
{
|
||||
if (!aFlags) {
|
||||
SetDOMStringToNull(aString);
|
||||
return;
|
||||
}
|
||||
|
||||
aString.Truncate();
|
||||
|
||||
#define SANDBOX_KEYWORD(string, atom, flags) \
|
||||
if (!(aFlags & (flags))) { \
|
||||
if (!aString.IsEmpty()) { \
|
||||
aString.Append(NS_LITERAL_STRING(" ")); \
|
||||
} \
|
||||
aString.Append(nsDependentAtomString(nsGkAtoms::atom)); \
|
||||
}
|
||||
#include "IframeSandboxKeywordList.h"
|
||||
#undef SANDBOX_KEYWORD
|
||||
}
|
||||
|
||||
nsIBidiKeyboard*
|
||||
nsContentUtils::GetBidiKeyboard()
|
||||
{
|
||||
|
@ -917,6 +917,34 @@ public:
|
||||
const char* aKey,
|
||||
nsXPIDLString& aResult);
|
||||
|
||||
/**
|
||||
* A helper function that parses a sandbox attribute (of an <iframe> or a CSP
|
||||
* directive) and converts it to the set of flags used internally.
|
||||
*
|
||||
* @param aSandboxAttr the sandbox attribute
|
||||
* @return the set of flags (SANDBOXED_NONE if aSandboxAttr is
|
||||
* null)
|
||||
*/
|
||||
static uint32_t ParseSandboxAttributeToFlags(const nsAttrValue* aSandboxAttr);
|
||||
|
||||
/**
|
||||
* A helper function that checks if a string matches a valid sandbox flag.
|
||||
*
|
||||
* @param aFlag the potential sandbox flag.
|
||||
* @return true if the flag is a sandbox flag.
|
||||
*/
|
||||
static bool IsValidSandboxFlag(const nsAString& aFlag);
|
||||
|
||||
/**
|
||||
* A helper function that returns a string attribute corresponding to the
|
||||
* sandbox flags.
|
||||
*
|
||||
* @param aFlags the sandbox flags
|
||||
* @param aString the attribute corresponding to the flags (null if aFlags
|
||||
* is zero)
|
||||
*/
|
||||
static void SandboxFlagsToString(uint32_t aFlags, nsAString& aString);
|
||||
|
||||
/**
|
||||
* Helper function that generates a UUID.
|
||||
*/
|
||||
|
@ -3214,6 +3214,10 @@ PrepareForFullscreenChange(nsIPresShell* aPresShell, const nsSize& aSize,
|
||||
}
|
||||
if (nsRefreshDriver* rd = aPresShell->GetRefreshDriver()) {
|
||||
rd->SetIsResizeSuppressed();
|
||||
// Since we are suppressing the resize reflow which would originally
|
||||
// be triggered by view manager, we need to ensure that the refresh
|
||||
// driver actually schedules a flush, otherwise it may get stuck.
|
||||
rd->ScheduleViewManagerFlush();
|
||||
}
|
||||
if (!aSize.IsEmpty()) {
|
||||
if (nsViewManager* viewManager = aPresShell->GetViewManager()) {
|
||||
|
@ -2758,6 +2758,8 @@ nsDocument::ApplySettingsFromCSP(bool aSpeculative)
|
||||
nsresult
|
||||
nsDocument::InitCSP(nsIChannel* aChannel)
|
||||
{
|
||||
MOZ_ASSERT(!mScriptGlobalObject,
|
||||
"CSP must be initialized before mScriptGlobalObject is set!");
|
||||
if (!CSPService::sCSPEnabled) {
|
||||
MOZ_LOG(gCspPRLog, LogLevel::Debug,
|
||||
("CSP is disabled, skipping CSP init for document %p", this));
|
||||
@ -2790,7 +2792,7 @@ nsDocument::InitCSP(nsIChannel* aChannel)
|
||||
NS_ConvertASCIItoUTF16 cspROHeaderValue(tCspROHeaderValue);
|
||||
|
||||
// Figure out if we need to apply an app default CSP or a CSP from an app manifest
|
||||
nsIPrincipal* principal = NodePrincipal();
|
||||
nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
|
||||
|
||||
uint16_t appStatus = principal->GetAppStatus();
|
||||
bool applyAppDefaultCSP = false;
|
||||
@ -2939,6 +2941,24 @@ nsDocument::InitCSP(nsIChannel* aChannel)
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// ----- Enforce sandbox policy if supplied in CSP header
|
||||
// The document may already have some sandbox flags set (e.g. if the document
|
||||
// is an iframe with the sandbox attribute set). If we have a CSP sandbox
|
||||
// directive, intersect the CSP sandbox flags with the existing flags. This
|
||||
// corresponds to the _least_ permissive policy.
|
||||
uint32_t cspSandboxFlags = SANDBOXED_NONE;
|
||||
rv = csp->GetCSPSandboxFlags(&cspSandboxFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mSandboxFlags |= cspSandboxFlags;
|
||||
|
||||
if (cspSandboxFlags & SANDBOXED_ORIGIN) {
|
||||
// If the new CSP sandbox flags do not have the allow-same-origin flag
|
||||
// reset the document principal to a null principal
|
||||
principal = do_CreateInstance("@mozilla.org/nullprincipal;1");
|
||||
SetPrincipal(principal);
|
||||
}
|
||||
|
||||
// ----- Enforce frame-ancestor policy on any applied policies
|
||||
nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
|
||||
if (docShell) {
|
||||
@ -3670,6 +3690,12 @@ nsDocument::RemoveCharSetObserver(nsIObserver* aObserver)
|
||||
mCharSetObservers.RemoveElement(aObserver);
|
||||
}
|
||||
|
||||
void
|
||||
nsIDocument::GetSandboxFlagsAsString(nsAString& aFlags)
|
||||
{
|
||||
nsContentUtils::SandboxFlagsToString(mSandboxFlags, aFlags);
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::GetHeaderData(nsIAtom* aHeaderField, nsAString& aData) const
|
||||
{
|
||||
@ -11658,7 +11684,7 @@ nsDocument::FullScreenStackPop()
|
||||
while (!mFullScreenStack.IsEmpty()) {
|
||||
Element* element = FullScreenStackTop();
|
||||
if (!element || !element->IsInUncomposedDoc() || element->OwnerDoc() != this) {
|
||||
NS_ASSERTION(!element->IsFullScreenAncestor(),
|
||||
NS_ASSERTION(!element->State().HasState(NS_EVENT_STATE_FULL_SCREEN),
|
||||
"Should have already removed full-screen styles");
|
||||
uint32_t last = mFullScreenStack.Length() - 1;
|
||||
mFullScreenStack.RemoveElementAt(last);
|
||||
@ -12220,7 +12246,7 @@ nsDocument::GetFullscreenElement()
|
||||
{
|
||||
Element* element = FullScreenStackTop();
|
||||
NS_ASSERTION(!element ||
|
||||
element->IsFullScreenAncestor(),
|
||||
element->State().HasState(NS_EVENT_STATE_FULL_SCREEN),
|
||||
"Fullscreen element should have fullscreen styles applied");
|
||||
return element;
|
||||
}
|
||||
|
@ -696,6 +696,11 @@ public:
|
||||
return mSandboxFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get string representation of sandbox flags (null if no flags are set)
|
||||
*/
|
||||
void GetSandboxFlagsAsString(nsAString& aFlags);
|
||||
|
||||
/**
|
||||
* Set the sandbox flags for this document.
|
||||
* @see nsSandboxFlags.h for the possible flags
|
||||
|
@ -721,7 +721,8 @@ nsObjectLoadingContent::nsObjectLoadingContent()
|
||||
, mActivated(false)
|
||||
, mIsStopping(false)
|
||||
, mIsLoading(false)
|
||||
, mScriptRequested(false) {}
|
||||
, mScriptRequested(false)
|
||||
, mRewrittenYoutubeEmbed(false) {}
|
||||
|
||||
nsObjectLoadingContent::~nsObjectLoadingContent()
|
||||
{
|
||||
@ -1843,6 +1844,7 @@ nsObjectLoadingContent::UpdateObjectParameters(bool aJavaURI)
|
||||
NS_NOTREACHED("Unrecognized plugin-loading tag");
|
||||
}
|
||||
|
||||
mRewrittenYoutubeEmbed = false;
|
||||
// Note that the baseURI changing could affect the newURI, even if uriStr did
|
||||
// not change.
|
||||
if (!uriStr.IsEmpty()) {
|
||||
@ -1856,6 +1858,7 @@ nsObjectLoadingContent::UpdateObjectParameters(bool aJavaURI)
|
||||
getter_AddRefs(rewrittenURI));
|
||||
if (rewrittenURI) {
|
||||
newURI = rewrittenURI;
|
||||
mRewrittenYoutubeEmbed = true;
|
||||
newMime = NS_LITERAL_CSTRING("text/html");
|
||||
}
|
||||
|
||||
|
@ -250,6 +250,11 @@ class nsObjectLoadingContent : public nsImageLoadingContent
|
||||
return runID;
|
||||
}
|
||||
|
||||
bool IsRewrittenYoutubeEmbed() const
|
||||
{
|
||||
return mRewrittenYoutubeEmbed;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Begins loading the object when called
|
||||
@ -628,7 +633,7 @@ class nsObjectLoadingContent : public nsImageLoadingContent
|
||||
FallbackType mFallbackType : 8;
|
||||
|
||||
uint32_t mRunID;
|
||||
bool mHasRunID;
|
||||
bool mHasRunID : 1;
|
||||
|
||||
// If true, we have opened a channel as the listener and it has reached
|
||||
// OnStartRequest. Does not get set for channels that are passed directly to
|
||||
@ -658,6 +663,12 @@ class nsObjectLoadingContent : public nsImageLoadingContent
|
||||
// whether content js has tried to access the plugin script object.
|
||||
bool mScriptRequested : 1;
|
||||
|
||||
// True if object represents an object/embed tag pointing to a flash embed
|
||||
// for a youtube video. When possible (see IsRewritableYoutubeEmbed function
|
||||
// comments for details), we change these to try to load HTML5 versions of
|
||||
// videos.
|
||||
bool mRewrittenYoutubeEmbed : 1;
|
||||
|
||||
nsWeakFrame mPrintFrame;
|
||||
|
||||
RefPtr<nsPluginInstanceOwner> mInstanceOwner;
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include "nsIWeakReference.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIDocument.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@ -66,7 +68,8 @@ NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginArray,
|
||||
mWindow,
|
||||
mPlugins)
|
||||
mPlugins,
|
||||
mCTPPlugins)
|
||||
|
||||
static void
|
||||
GetPluginMimeTypes(const nsTArray<RefPtr<nsPluginElement> >& aPlugins,
|
||||
@ -146,6 +149,7 @@ nsPluginArray::Refresh(bool aReloadDocuments)
|
||||
}
|
||||
|
||||
mPlugins.Clear();
|
||||
mCTPPlugins.Clear();
|
||||
|
||||
nsCOMPtr<nsIDOMNavigator> navigator = mWindow->GetNavigator();
|
||||
|
||||
@ -221,6 +225,13 @@ nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound)
|
||||
|
||||
nsPluginElement* plugin = FindPlugin(mPlugins, aName);
|
||||
aFound = (plugin != nullptr);
|
||||
if (!aFound) {
|
||||
nsPluginElement* hiddenPlugin = FindPlugin(mCTPPlugins, aName);
|
||||
if (hiddenPlugin) {
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
obs->NotifyObservers(hiddenPlugin->PluginTag(), "Plugin::HiddenPluginTouched", nsString(aName).get());
|
||||
}
|
||||
}
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@ -282,7 +293,7 @@ operator<(const RefPtr<nsPluginElement>& lhs,
|
||||
void
|
||||
nsPluginArray::EnsurePlugins()
|
||||
{
|
||||
if (!mPlugins.IsEmpty()) {
|
||||
if (!mPlugins.IsEmpty() || !mCTPPlugins.IsEmpty()) {
|
||||
// We already have an array of plugin elements.
|
||||
return;
|
||||
}
|
||||
@ -299,7 +310,31 @@ nsPluginArray::EnsurePlugins()
|
||||
// need to wrap each of these with a nsPluginElement, which is
|
||||
// scriptable.
|
||||
for (uint32_t i = 0; i < pluginTags.Length(); ++i) {
|
||||
mPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i]));
|
||||
nsCOMPtr<nsPluginTag> pluginTag = do_QueryInterface(pluginTags[i]);
|
||||
if (!pluginTag) {
|
||||
mPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i]));
|
||||
} else if (pluginTag->IsActive()) {
|
||||
uint32_t permission = nsIPermissionManager::ALLOW_ACTION;
|
||||
if (pluginTag->IsClicktoplay()) {
|
||||
nsCString name;
|
||||
pluginTag->GetName(name);
|
||||
if (NS_LITERAL_CSTRING("Shockwave Flash").Equals(name)) {
|
||||
RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
|
||||
nsCString permString;
|
||||
nsresult rv = pluginHost->GetPermissionStringForTag(pluginTag, 0, permString);
|
||||
if (rv == NS_OK) {
|
||||
nsIPrincipal* principal = mWindow->GetExtantDoc()->NodePrincipal();
|
||||
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
|
||||
permMgr->TestPermissionFromPrincipal(principal, permString.get(), &permission);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (permission == nsIPermissionManager::ALLOW_ACTION) {
|
||||
mPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i]));
|
||||
} else {
|
||||
mCTPPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Alphabetize the enumeration order of non-hidden plugins to reduce
|
||||
|
@ -60,6 +60,10 @@ private:
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> mWindow;
|
||||
nsTArray<RefPtr<nsPluginElement> > mPlugins;
|
||||
/* A separate list of click-to-play plugins that we don't tell content
|
||||
* about but keep track of so we can still prompt the user to click to play.
|
||||
*/
|
||||
nsTArray<RefPtr<nsPluginElement> > mCTPPlugins;
|
||||
};
|
||||
|
||||
class nsPluginElement final : public nsISupports,
|
||||
|
@ -12,6 +12,11 @@
|
||||
#ifndef nsSandboxFlags_h___
|
||||
#define nsSandboxFlags_h___
|
||||
|
||||
/**
|
||||
* This constant denotes the lack of a sandbox attribute/directive.
|
||||
*/
|
||||
const unsigned long SANDBOXED_NONE = 0x0;
|
||||
|
||||
/**
|
||||
* This flag prevents content from navigating browsing contexts other than
|
||||
* itself, browsing contexts nested inside it, the top-level browsing context
|
||||
|
65
dom/base/test/file_youtube_flash_embed.html
Normal file
65
dom/base/test/file_youtube_flash_embed.html
Normal file
@ -0,0 +1,65 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1240471
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1240471</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
let SimpleTest = {
|
||||
finish: function() {
|
||||
parent.postMessage(JSON.stringify({fn: "finish"}), "*");
|
||||
}
|
||||
};
|
||||
["ok", "is", "info"].forEach(fn => {
|
||||
self[fn] = function (...args) {
|
||||
parent.postMessage(JSON.stringify({fn: fn, args: args}), "*");
|
||||
}
|
||||
});
|
||||
"use strict";
|
||||
function onLoad() {
|
||||
let youtube_changed_url_query = "https://mochitest.youtube.com/embed/Xm5i5kbIXzc?start=10&end=20";
|
||||
|
||||
function testEmbed(embed, expected_url, expected_fullscreen) {
|
||||
ok (!!embed, "Embed node exists");
|
||||
// getSVGDocument will return HTMLDocument if the content is HTML
|
||||
let doc = embed.getSVGDocument();
|
||||
// doc must be unprivileged because privileged doc will always be
|
||||
// allowed to use fullscreen.
|
||||
is (doc.fullscreenEnabled, expected_fullscreen,
|
||||
"fullscreen should be " + (expected_fullscreen ? "enabled" : "disabled"));
|
||||
embed = SpecialPowers.wrap(embed);
|
||||
is (embed.srcURI.spec, expected_url, "Should have src uri of " + expected_url);
|
||||
}
|
||||
info("Running youtube rewrite query test");
|
||||
testEmbed(document.getElementById("testembed-correct"), youtube_changed_url_query, false);
|
||||
testEmbed(document.getElementById("testembed-correct-fs"), youtube_changed_url_query, true);
|
||||
testEmbed(document.getElementById("testembed-wrong"), youtube_changed_url_query, false);
|
||||
testEmbed(document.getElementById("testembed-whywouldyouevendothat"), youtube_changed_url_query, true);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="onLoad()">
|
||||
<embed id="testembed-correct"
|
||||
src="https://mochitest.youtube.com/v/Xm5i5kbIXzc?start=10&end=20"
|
||||
type="application/x-shockwave-flash"
|
||||
allowscriptaccess="always"></embed>
|
||||
<embed id="testembed-correct-fs"
|
||||
src="https://mochitest.youtube.com/v/Xm5i5kbIXzc?start=10&end=20"
|
||||
type="application/x-shockwave-flash"
|
||||
allowfullscreen
|
||||
allowscriptaccess="always"></embed>
|
||||
<embed id="testembed-wrong"
|
||||
src="https://mochitest.youtube.com/v/Xm5i5kbIXzc&start=10&end=20"
|
||||
type="application/x-shockwave-flash"
|
||||
allowscriptaccess="always"></embed>
|
||||
<embed id="testembed-whywouldyouevendothat"
|
||||
src="https://mochitest.youtube.com/v/Xm5i5kbIXzc&start=10?end=20"
|
||||
type="application/x-shockwave-flash"
|
||||
allowfullscreen
|
||||
allowscriptaccess="always"></embed>
|
||||
</body>
|
||||
</html>
|
@ -189,6 +189,7 @@ support-files =
|
||||
file_xhtmlserializer_2_enthtml.xhtml
|
||||
file_xhtmlserializer_2_entw3c.xhtml
|
||||
file_xhtmlserializer_2_latin1.xhtml
|
||||
file_youtube_flash_embed.html
|
||||
fileapi_chromeScript.js
|
||||
fileutils.js
|
||||
forRemoval.resource
|
||||
|
@ -10,35 +10,23 @@
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
"use strict";
|
||||
function onLoad () {
|
||||
let youtube_changed_url_query = "https://mochitest.youtube.com/embed/Xm5i5kbIXzc?start=10&end=20";
|
||||
|
||||
function testEmbed(embed, expected_url) {
|
||||
ok (embed, "Embed node exists");
|
||||
embed = SpecialPowers.wrap(embed);
|
||||
is (embed.srcURI.spec, expected_url, "Should have src uri of " + expected_url);
|
||||
let path = location.pathname.substring(0, location.pathname.lastIndexOf('/')) + '/file_youtube_flash_embed.html';
|
||||
onmessage = function(e) {
|
||||
let msg = JSON.parse(e.data);
|
||||
if (msg.fn == "finish") {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
info("Running youtube rewrite query test");
|
||||
testEmbed(document.getElementById("testembed-correct"), youtube_changed_url_query);
|
||||
testEmbed(document.getElementById("testembed-wrong"), youtube_changed_url_query);
|
||||
testEmbed(document.getElementById("testembed-whywouldyouevendothat"), youtube_changed_url_query);
|
||||
SimpleTest.finish();
|
||||
self[msg.fn].apply(null, msg.args);
|
||||
}
|
||||
function onLoad() {
|
||||
// The test file must be loaded into youtube.com domain
|
||||
// because it needs unprivileged access to fullscreenEnabled.
|
||||
ifr.src = "https://mochitest.youtube.com" + path;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="onLoad()">
|
||||
<embed id="testembed-correct"
|
||||
src="https://mochitest.youtube.com/v/Xm5i5kbIXzc?start=10&end=20"
|
||||
type="application/x-shockwave-flash"
|
||||
allowscriptaccess="always"></embed>
|
||||
<embed id="testembed-wrong"
|
||||
src="https://mochitest.youtube.com/v/Xm5i5kbIXzc&start=10&end=20"
|
||||
type="application/x-shockwave-flash"
|
||||
allowscriptaccess="always"></embed>
|
||||
<embed id="testembed-whywouldyouevendothat"
|
||||
src="https://mochitest.youtube.com/v/Xm5i5kbIXzc&start=10?end=20"
|
||||
type="application/x-shockwave-flash"
|
||||
allowscriptaccess="always"></embed>
|
||||
<iframe id="ifr" allowfullscreen></iframe>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -241,12 +241,12 @@ IsNotDateOrRegExp(JSContext* cx, JS::Handle<JSObject*> obj,
|
||||
{
|
||||
MOZ_ASSERT(obj);
|
||||
|
||||
js::ESClassValue cls;
|
||||
js::ESClass cls;
|
||||
if (!js::GetBuiltinClass(cx, obj, &cls)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*notDateOrRegExp = cls != js::ESClass_Date && cls != js::ESClass_RegExp;
|
||||
*notDateOrRegExp = cls != js::ESClass::Date && cls != js::ESClass::RegExp;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -55,12 +55,6 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
namespace workers {
|
||||
extern bool IsCurrentThreadRunningChromeWorker();
|
||||
} // namespace workers
|
||||
} // namespace dom
|
||||
|
||||
using namespace dom;
|
||||
using namespace hal;
|
||||
|
||||
@ -1344,24 +1338,6 @@ EventListenerManager::Disconnect()
|
||||
RemoveAllListeners();
|
||||
}
|
||||
|
||||
static EventListenerFlags
|
||||
GetEventListenerFlagsFromOptions(const EventListenerOptions& aOptions,
|
||||
bool aIsMainThread)
|
||||
{
|
||||
EventListenerFlags flags;
|
||||
flags.mCapture = aOptions.mCapture;
|
||||
if (aOptions.mMozSystemGroup) {
|
||||
if (aIsMainThread) {
|
||||
JSContext* cx = nsContentUtils::GetCurrentJSContext();
|
||||
MOZ_ASSERT(cx, "Not being called from JS?");
|
||||
flags.mInSystemGroup = IsChromeOrXBL(cx, nullptr);
|
||||
} else {
|
||||
flags.mInSystemGroup = workers::IsCurrentThreadRunningChromeWorker();
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
void
|
||||
EventListenerManager::AddEventListener(
|
||||
const nsAString& aType,
|
||||
@ -1387,7 +1363,8 @@ EventListenerManager::AddEventListener(
|
||||
flags.mCapture = aOptions.GetAsBoolean();
|
||||
} else {
|
||||
const auto& options = aOptions.GetAsAddEventListenerOptions();
|
||||
flags = GetEventListenerFlagsFromOptions(options, mIsMainThreadELM);
|
||||
flags.mCapture = options.mCapture;
|
||||
flags.mInSystemGroup = options.mMozSystemGroup;
|
||||
flags.mPassive = options.mPassive;
|
||||
}
|
||||
flags.mAllowUntrustedEvents = aWantsUntrusted;
|
||||
@ -1416,7 +1393,8 @@ EventListenerManager::RemoveEventListener(
|
||||
flags.mCapture = aOptions.GetAsBoolean();
|
||||
} else {
|
||||
const auto& options = aOptions.GetAsEventListenerOptions();
|
||||
flags = GetEventListenerFlagsFromOptions(options, mIsMainThreadELM);
|
||||
flags.mCapture = options.mCapture;
|
||||
flags.mInSystemGroup = options.mMozSystemGroup;
|
||||
}
|
||||
RemoveEventListenerByType(aListenerHolder, aType, flags);
|
||||
}
|
||||
|
@ -4817,26 +4817,11 @@ static nsIContent* FindCommonAncestor(nsIContent *aNode1, nsIContent *aNode2)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static Element*
|
||||
GetParentElement(Element* aElement)
|
||||
{
|
||||
nsIContent* p = aElement->GetParent();
|
||||
return (p && p->IsElement()) ? p->AsElement() : nullptr;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
EventStateManager::SetFullScreenState(Element* aElement, bool aIsFullScreen)
|
||||
{
|
||||
DoStateChange(aElement, NS_EVENT_STATE_FULL_SCREEN, aIsFullScreen);
|
||||
Element* ancestor = aElement;
|
||||
while ((ancestor = GetParentElement(ancestor))) {
|
||||
DoStateChange(ancestor, NS_EVENT_STATE_FULL_SCREEN_ANCESTOR, aIsFullScreen);
|
||||
if (ancestor->State().HasState(NS_EVENT_STATE_FULL_SCREEN)) {
|
||||
// If we meet another fullscreen element, stop here.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
@ -262,8 +262,8 @@ private:
|
||||
// Content is the full screen element, or a frame containing the
|
||||
// current full-screen element.
|
||||
#define NS_EVENT_STATE_FULL_SCREEN NS_DEFINE_EVENT_STATE_MACRO(33)
|
||||
// Content is an ancestor of the DOM full-screen element.
|
||||
#define NS_EVENT_STATE_FULL_SCREEN_ANCESTOR NS_DEFINE_EVENT_STATE_MACRO(34)
|
||||
// This bit is currently free.
|
||||
// #define NS_EVENT_STATE_?????????? NS_DEFINE_EVENT_STATE_MACRO(34)
|
||||
// Handler for click to play plugin
|
||||
#define NS_EVENT_STATE_TYPE_CLICK_TO_PLAY NS_DEFINE_EVENT_STATE_MACRO(35)
|
||||
// Content is in the optimum region.
|
||||
@ -299,8 +299,7 @@ private:
|
||||
#define ESM_MANAGED_STATES (NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS | \
|
||||
NS_EVENT_STATE_HOVER | NS_EVENT_STATE_DRAGOVER | \
|
||||
NS_EVENT_STATE_URLTARGET | NS_EVENT_STATE_FOCUSRING | \
|
||||
NS_EVENT_STATE_FULL_SCREEN | NS_EVENT_STATE_FULL_SCREEN_ANCESTOR | \
|
||||
NS_EVENT_STATE_UNRESOLVED)
|
||||
NS_EVENT_STATE_FULL_SCREEN | NS_EVENT_STATE_UNRESOLVED)
|
||||
|
||||
#define INTRINSIC_STATES (~ESM_MANAGED_STATES)
|
||||
|
||||
|
@ -242,17 +242,10 @@ HTMLIFrameElement::GetSandboxFlags()
|
||||
const nsAttrValue* sandboxAttr = GetParsedAttr(nsGkAtoms::sandbox);
|
||||
// No sandbox attribute, no sandbox flags.
|
||||
if (!sandboxAttr) {
|
||||
return 0;
|
||||
return SANDBOXED_NONE;
|
||||
}
|
||||
|
||||
// Start off by setting all the restriction flags.
|
||||
uint32_t out = SANDBOX_ALL_FLAGS;
|
||||
|
||||
// Macro for updating the flag according to the keywords
|
||||
#define SANDBOX_KEYWORD(string, atom, flags) \
|
||||
if (sandboxAttr->Contains(nsGkAtoms::atom, eIgnoreCase)) { out &= ~(flags); }
|
||||
#include "IframeSandboxKeywordList.h"
|
||||
#undef SANDBOX_KEYWORD
|
||||
uint32_t out = nsContentUtils::ParseSandboxAttributeToFlags(sandboxAttr);
|
||||
|
||||
if (GetParsedAttr(nsGkAtoms::allowfullscreen) ||
|
||||
GetParsedAttr(nsGkAtoms::mozallowfullscreen)) {
|
||||
|
@ -3165,7 +3165,13 @@ HTMLInputElement::GetDisplayFileName(nsAString& aValue) const
|
||||
nsXPIDLString value;
|
||||
|
||||
if (mFilesOrDirectories.IsEmpty()) {
|
||||
if (HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)) {
|
||||
if ((Preferences::GetBool("dom.input.dirpicker", false) &&
|
||||
HasAttr(kNameSpaceID_None, nsGkAtoms::directory)) ||
|
||||
(Preferences::GetBool("dom.webkitBlink.dirPicker.enabled", false) &&
|
||||
HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory))) {
|
||||
nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
|
||||
"NoDirSelected", value);
|
||||
} else if (HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)) {
|
||||
nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
|
||||
"NoFilesSelected", value);
|
||||
} else {
|
||||
@ -4405,12 +4411,10 @@ HTMLInputElement::MaybeInitPickers(EventChainPostVisitor& aVisitor)
|
||||
if (target &&
|
||||
target->GetParent() == this &&
|
||||
target->IsRootOfNativeAnonymousSubtree() &&
|
||||
(target->HasAttr(kNameSpaceID_None, nsGkAtoms::directory) ||
|
||||
target->HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory))) {
|
||||
MOZ_ASSERT(Preferences::GetBool("dom.input.dirpicker", false) ||
|
||||
Preferences::GetBool("dom.webkitBlink.dirPicker.enabled", false),
|
||||
"No API or UI should have been exposed to allow this code to "
|
||||
"be reached");
|
||||
((Preferences::GetBool("dom.input.dirpicker", false) &&
|
||||
HasAttr(kNameSpaceID_None, nsGkAtoms::directory)) ||
|
||||
(Preferences::GetBool("dom.webkitBlink.dirPicker.enabled", false) &&
|
||||
HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory)))) {
|
||||
type = FILE_PICKER_DIRECTORY;
|
||||
}
|
||||
return InitFilePicker(type);
|
||||
|
@ -155,12 +155,6 @@ function enter4(event) {
|
||||
is(event.target, document, "Event target should be full-screen document #5");
|
||||
is(document.fullscreenElement, inDocElement, "FSE should be inDocElement.");
|
||||
|
||||
var n = container;
|
||||
do {
|
||||
ok(n.matches(":-moz-full-screen-ancestor"), "Ancestor " + n + " should match :-moz-full-screen-ancestor")
|
||||
n = n.parentNode;
|
||||
} while (n && n.matches);
|
||||
|
||||
// Remove full-screen ancestor element from document, verify it stops being reported as current FSE.
|
||||
addFullscreenChangeContinuation("exit", exit_to_arg_test_1);
|
||||
container.parentNode.removeChild(container);
|
||||
|
17
dom/html/test/file_iframe_sandbox_c_if9.html
Normal file
17
dom/html/test/file_iframe_sandbox_c_if9.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 671389</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
I am
|
||||
<ul>
|
||||
<li>sandboxed but with "allow-forms", "allow-pointer-lock", "allow-popups", "allow-same-origin", "allow-scripts", and "allow-top-navigation", </li>
|
||||
<li>sandboxed but with "allow-same-origin", "allow-scripts", </li>
|
||||
<li>sandboxed, or </li>
|
||||
<li>not sandboxed.</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
@ -98,6 +98,7 @@ support-files =
|
||||
file_iframe_sandbox_c_if6.html
|
||||
file_iframe_sandbox_c_if7.html
|
||||
file_iframe_sandbox_c_if8.html
|
||||
file_iframe_sandbox_c_if9.html
|
||||
file_iframe_sandbox_close.html
|
||||
file_iframe_sandbox_d_if1.html
|
||||
file_iframe_sandbox_d_if10.html
|
||||
|
@ -41,7 +41,7 @@ function ok_wrapper(result, desc) {
|
||||
passedTests++;
|
||||
}
|
||||
|
||||
if (completedTests == 27) {
|
||||
if (completedTests == 33) {
|
||||
is(passedTests, completedTests, "There are " + completedTests + " general tests that should pass");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
@ -180,6 +180,14 @@ function doTest() {
|
||||
// This is done via file_iframe_sandbox_c_if4.html which is sandboxed with "allow-scripts" and "allow-same-origin"
|
||||
// the window it attempts to open calls window.opener.ok(false, ...) and file_iframe_c_if4.html has an ok()
|
||||
// function that calls window.parent.ok_wrapper.
|
||||
|
||||
// passes twice if good
|
||||
// 29-32) Test that sandboxFlagsAsString returns the set flags.
|
||||
// see if_14 and if_15
|
||||
|
||||
// passes once if good
|
||||
// 33) Test that sandboxFlagsAsString returns null if iframe does not have sandbox flag set.
|
||||
// see if_16
|
||||
}
|
||||
|
||||
addLoadEvent(doTest);
|
||||
@ -212,6 +220,36 @@ function do_if_10() {
|
||||
var if_10 = document.getElementById('if_10');
|
||||
if_10.src = 'javascript:"<html><script>window.parent.ok_wrapper(true, \'an iframe sandboxed with allow-scripts should execute script in a javascript URL in a newly set src attribute\');<\/script><\/html>"';
|
||||
}
|
||||
|
||||
function eqFlags(a, b) {
|
||||
// both a and b should be either null or have the array same flags
|
||||
if (a === null && b === null) { return true; }
|
||||
if (a === null || b === null) { return false; }
|
||||
if (a.length !== b.length) { return false; }
|
||||
var a_sorted = a.sort();
|
||||
var b_sorted = b.sort();
|
||||
for (var i in a_sorted) {
|
||||
if (a_sorted[i] !== b_sorted[i]) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function getSandboxFlags(doc) {
|
||||
var flags = doc.sandboxFlagsAsString;
|
||||
if (flags === null) { return null; }
|
||||
return flags? flags.split(" "):[];
|
||||
}
|
||||
|
||||
function test_sandboxFlagsAsString(name, expected) {
|
||||
var ifr = document.getElementById(name);
|
||||
try {
|
||||
var flags = getSandboxFlags(SpecialPowers.wrap(ifr).contentDocument);
|
||||
ok_wrapper(eqFlags(flags, expected), name + ' expected: "' + expected + '", got: "' + flags + '"');
|
||||
} catch (e) {
|
||||
ok_wrapper(false, name + ' expected "' + expected + ', but failed with ' + e);
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=341604">Mozilla Bug 341604</a> - Implement HTML5 sandbox attribute for IFRAMEs
|
||||
@ -234,6 +272,10 @@ function do_if_10() {
|
||||
<iframe sandbox="allow-same-origin allow-scripts" onload='start_if_10()' id='if_10' src="about:blank" height="10" width="10"></iframe>
|
||||
<iframe sandbox="allow-scripts" id='if_11' src="file_iframe_sandbox_c_if7.html" height="10" width="10"></iframe>
|
||||
<iframe sandbox="allow-same-origin allow-scripts" id='if_12' src="file_iframe_sandbox_c_if8.html" height="10" width="10"></iframe>
|
||||
<iframe sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-top-navigation " id='if_13' src="file_iframe_sandbox_c_if9.html" height="10" width="10" onload='test_sandboxFlagsAsString("if_13",["allow-forms", "allow-pointer-lock", "allow-popups", "allow-same-origin", "allow-scripts", "allow-top-navigation"])'></iframe>
|
||||
<iframe sandbox="	allow-same-origin	allow-scripts	" id="if_14" src="file_iframe_sandbox_c_if6.html" height="10" width="10" onload='test_sandboxFlagsAsString("if_14",["allow-same-origin","allow-scripts"])'></iframe>
|
||||
<iframe sandbox="" id="if_15" src="file_iframe_sandbox_c_if9.html" height="10" width="10" onload='test_sandboxFlagsAsString("if_15",[])'></iframe>
|
||||
<iframe id="if_16" src="file_iframe_sandbox_c_if9.html" height="10" width="10" onload='test_sandboxFlagsAsString("if_16",null)'></iframe>
|
||||
<input type='button' id="a_button" onclick='do_if_9()'>
|
||||
<input type='button' id="a_button2" onclick='do_if_10()'>
|
||||
</div>
|
||||
|
@ -111,11 +111,11 @@ IDBKeyRange::FromJSVal(JSContext* aCx,
|
||||
JS::Rooted<JSObject*> obj(aCx, aVal.isObject() ? &aVal.toObject() : nullptr);
|
||||
bool isValidKey = aVal.isPrimitive();
|
||||
if (!isValidKey) {
|
||||
js::ESClassValue cls;
|
||||
js::ESClass cls;
|
||||
if (!js::GetBuiltinClass(aCx, obj, &cls)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
isValidKey = cls == js::ESClass_Array || cls == js::ESClass_Date;
|
||||
isValidKey = cls == js::ESClass::Array || cls == js::ESClass::Date;
|
||||
}
|
||||
if (isValidKey) {
|
||||
// A valid key returns an 'only' IDBKeyRange.
|
||||
|
@ -232,12 +232,12 @@ Key::EncodeJSValInternal(JSContext* aCx, JS::Handle<JS::Value> aVal,
|
||||
if (aVal.isObject()) {
|
||||
JS::Rooted<JSObject*> obj(aCx, &aVal.toObject());
|
||||
|
||||
js::ESClassValue cls;
|
||||
js::ESClass cls;
|
||||
if (!js::GetBuiltinClass(aCx, obj, &cls)) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
if (cls == js::ESClass_Array) {
|
||||
if (cls == js::ESClass::Array) {
|
||||
aTypeOffset += eMaxType;
|
||||
|
||||
if (aTypeOffset == eMaxType * kMaxArrayCollapse) {
|
||||
@ -275,7 +275,7 @@ Key::EncodeJSValInternal(JSContext* aCx, JS::Handle<JS::Value> aVal,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (cls == js::ESClass_Date) {
|
||||
if (cls == js::ESClass::Date) {
|
||||
bool valid;
|
||||
if (!js::DateIsValid(aCx, obj, &valid)) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
|
@ -60,6 +60,7 @@ interface nsIContentSecurityPolicy : nsISerializable
|
||||
const unsigned short CHILD_SRC_DIRECTIVE = 18;
|
||||
const unsigned short BLOCK_ALL_MIXED_CONTENT = 19;
|
||||
const unsigned short REQUIRE_SRI_FOR = 20;
|
||||
const unsigned short SANDBOX_DIRECTIVE = 21;
|
||||
|
||||
/**
|
||||
* Accessor method for a read-only string version of the policy at a given
|
||||
@ -157,6 +158,17 @@ interface nsIContentSecurityPolicy : nsISerializable
|
||||
*/
|
||||
boolean getAllowsEval(out boolean shouldReportViolations);
|
||||
|
||||
/**
|
||||
* Delegate method called by the service when the protected document is loaded.
|
||||
* Returns the union of all the sandbox flags contained in CSP policies. This is the most
|
||||
* restrictive interpretation of flags set in multiple policies.
|
||||
* See nsSandboxFlags.h for the possible flags.
|
||||
*
|
||||
* @return
|
||||
* sandbox flags or SANDBOXED_NONE if no sandbox directive exists
|
||||
*/
|
||||
uint32_t getCSPSandboxFlags();
|
||||
|
||||
/**
|
||||
* For each violated policy (of type violationType), log policy violation on
|
||||
* the Error Console and send a report to report-uris present in the violated
|
||||
|
@ -5,8 +5,6 @@
|
||||
Reset=Reset
|
||||
Submit=Submit Query
|
||||
Browse=Browse…
|
||||
ChooseFiles=Choose files…
|
||||
ChooseDirs=Choose folder…
|
||||
FileUpload=File Upload
|
||||
# LOCALIZATION NOTE (IsIndexPromptWithSpace): The last character of the string
|
||||
# should be a space (U+0020) in most locales. The prompt is followed by an
|
||||
@ -25,6 +23,10 @@ NoFileSelected=No file selected.
|
||||
# LOCALIZATION NOTE (NoFilesSelected): this string is shown on a
|
||||
# <input type='file' multiple> when there is no file selected yet.
|
||||
NoFilesSelected=No files selected.
|
||||
# LOCALIZATION NOTE (NoDirSelected): this string is shown on a
|
||||
# <input type='file' directory/webkitdirectory> when there is no directory
|
||||
# selected yet.
|
||||
NoDirSelected=No directory selected.
|
||||
# LOCALIZATION NOTE (XFilesSelected): this string is shown on a
|
||||
# <input type='file' multiple> when there are more than one selected file.
|
||||
# %S will be a number greater or equal to 2.
|
||||
|
@ -74,6 +74,9 @@ blockAllMixedContent = Blocking insecure request ‘%1$S’.
|
||||
# LOCALIZATION NOTE (ignoringDirectiveWithNoValues):
|
||||
# %1$S is the name of a CSP directive that requires additional values (e.g., 'require-sri-for')
|
||||
ignoringDirectiveWithNoValues = Ignoring ‘%1$S’ since it does not contain any parameters.
|
||||
# LOCALIZATION NOTE (ignoringReportOnlyDirective):
|
||||
# %1$S is the directive that is ignored in report-only mode.
|
||||
ignoringReportOnlyDirective = Ignoring sandbox directive when delivered in a report-only policy ‘%1$S’
|
||||
|
||||
# CSP Errors:
|
||||
# LOCALIZATION NOTE (couldntParseInvalidSource):
|
||||
@ -94,3 +97,6 @@ duplicateDirective = Duplicate %1$S directives detected. All but the first inst
|
||||
# LOCALIZATION NOTE (deprecatedDirective):
|
||||
# %1$S is the name of the deprecated directive, %2$S is the name of the replacement.
|
||||
deprecatedDirective = Directive ‘%1$S’ has been deprecated. Please use directive ‘%2$S’ instead.
|
||||
# LOCALIZATION NOTE (couldntParseInvalidSandboxFlag):
|
||||
# %1$S is the option that could not be understood
|
||||
couldntParseInvalidSandboxFlag = Couldn’t parse invalid sandbox flag ‘%1$S’
|
||||
|
@ -1,5 +1,5 @@
|
||||
//Used by JSHint:
|
||||
/*global Cu, BrowserTestUtils, ok, add_task, PromiseMessage, gBrowser */
|
||||
/*global Cu, BrowserTestUtils, ok, add_task, gBrowser */
|
||||
"use strict";
|
||||
const { PromiseMessage } = Cu.import("resource://gre/modules/PromiseMessage.jsm", {});
|
||||
const testPath = "/browser/dom/manifest/test/file_reg_install_event.html";
|
||||
@ -7,21 +7,35 @@ const defaultURL = new URL("http://example.org/browser/dom/manifest/test/file_te
|
||||
const testURL = new URL(defaultURL);
|
||||
testURL.searchParams.append("file", testPath);
|
||||
|
||||
// Enable window.oninstall, so we can fire events at it.
|
||||
function enableOnInstallPref() {
|
||||
const ops = {
|
||||
"set": [
|
||||
["dom.manifest.oninstall", true],
|
||||
],
|
||||
};
|
||||
return SpecialPowers.pushPrefEnv(ops);
|
||||
}
|
||||
|
||||
// Send a message for the even to be fired.
|
||||
// This cause file_reg_install_event.html to be dynamically change.
|
||||
function* theTest(aBrowser) {
|
||||
aBrowser.allowEvents = true;
|
||||
// Resolves when we get a custom event with the correct name
|
||||
const responsePromise = new Promise((resolve) => {
|
||||
aBrowser.contentDocument.addEventListener("dom.manifest.oninstall", resolve);
|
||||
});
|
||||
const mm = aBrowser.messageManager;
|
||||
const msgKey = "DOM:Manifest:FireInstallEvent";
|
||||
const initialText = aBrowser.contentWindowAsCPOW.document.body.innerHTML.trim()
|
||||
is(initialText, '<h1 id="output">waiting for event</h1>', "should be waiting for event");
|
||||
const { data: { success } } = yield PromiseMessage.send(mm, msgKey);
|
||||
ok(success, "message sent and received successfully.");
|
||||
const eventText = aBrowser.contentWindowAsCPOW.document.body.innerHTML.trim();
|
||||
is(eventText, '<h1 id="output">event received!</h1>', "text of the page should have changed.");
|
||||
};
|
||||
const { detail: { result } } = yield responsePromise;
|
||||
ok(result, "the page sent us an acknowledgment as a custom event");
|
||||
}
|
||||
|
||||
// Open a tab and run the test
|
||||
add_task(function*() {
|
||||
yield enableOnInstallPref();
|
||||
let tabOptions = {
|
||||
gBrowser: gBrowser,
|
||||
url: testURL.href,
|
||||
|
@ -1,9 +1,15 @@
|
||||
<meta charset=utf-8>
|
||||
<script>
|
||||
window.addEventListener("install", (ev) => {
|
||||
"use strict";
|
||||
window.addEventListener("install", () => {
|
||||
document
|
||||
.querySelector("#output")
|
||||
.innerHTML = "event received!"
|
||||
.innerHTML = "event received!";
|
||||
// Send a custom event back to the browser
|
||||
// to acknowledge that we got this
|
||||
const detail = { result: true }
|
||||
const ev = new CustomEvent("dom.manifest.oninstall", { detail });
|
||||
document.dispatchEvent(ev);
|
||||
});
|
||||
</script>
|
||||
<link rel="manifest" href="file_manifest.json">
|
||||
<h1 id=output>waiting for event</h1>
|
||||
|
@ -3,42 +3,96 @@
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1265279
|
||||
-->
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1265279 - Web Manifest: Implement window.oninstall</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
|
||||
<script>
|
||||
"use strict";
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
is(window.hasOwnProperty("oninstall"), true, "window has own oninstall property");
|
||||
is(window.oninstall, null, "window install is initially set to null");
|
||||
"use strict";
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
const finish = SimpleTest.finish.bind(SimpleTest);
|
||||
enableOnInstallPref()
|
||||
.then(createIframe)
|
||||
.then(checkImplementation)
|
||||
.then(checkOnInstallEventFires)
|
||||
.then(checkAddEventListenerFires)
|
||||
.then(finish)
|
||||
.catch(err => {
|
||||
dump(`${err}: ${err.stack}`);
|
||||
finish();
|
||||
});
|
||||
|
||||
// Check that enumerable, configurable, and has a getter and setter
|
||||
const objDescriptor = Object.getOwnPropertyDescriptor(window, "oninstall");
|
||||
is(objDescriptor.enumerable, true, "is enumerable");
|
||||
is(objDescriptor.configurable, true, "is configurable");
|
||||
is(objDescriptor.hasOwnProperty("get"), true, "has getter");
|
||||
is(objDescriptor.hasOwnProperty("set"), true, "has setter");
|
||||
function enableOnInstallPref() {
|
||||
const ops = {
|
||||
"set": [
|
||||
["dom.manifest.oninstall", true],
|
||||
],
|
||||
};
|
||||
return SpecialPowers.pushPrefEnv(ops);
|
||||
}
|
||||
|
||||
// Test is we receive the event on window.install
|
||||
const customEv = new CustomEvent("install");
|
||||
window.oninstall = function handler(ev){
|
||||
window.oninstall = null;
|
||||
is(ev, customEv, "The events should be the same");
|
||||
testAddEventListener();
|
||||
};
|
||||
window.dispatchEvent(customEv);
|
||||
// WebIDL conditional annotations for an interface are evaluate once per
|
||||
// global, so we need to create an iframe to see the effects of calling
|
||||
// enableOnInstallPref().
|
||||
function createIframe() {
|
||||
return new Promise((resolve) => {
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.src = "about:blank";
|
||||
iframe.onload = () => resolve(iframe.contentWindow);
|
||||
document.body.appendChild(iframe);
|
||||
});
|
||||
}
|
||||
|
||||
// Test that it works with .addEventListener("install", f);
|
||||
function testAddEventListener(){
|
||||
const customEv2 = new CustomEvent("install");
|
||||
window.addEventListener("install", function handler2(ev2) {
|
||||
window.removeEventListener("install", handler2);
|
||||
is(ev2, customEv2, "The events should be the same");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
window.dispatchEvent(customEv2);
|
||||
}
|
||||
// Check that the WebIDL is as expected.
|
||||
function checkImplementation(ifrWindow) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const hasOnInstallProp = ifrWindow.hasOwnProperty("oninstall");
|
||||
ok(hasOnInstallProp, "window has own oninstall property");
|
||||
|
||||
// no point in continuing
|
||||
if (!hasOnInstallProp) {
|
||||
const err = new Error("No 'oninstall' IDL attribute. Aborting early.");
|
||||
return reject(err);
|
||||
}
|
||||
is(ifrWindow.oninstall, null, "window install is initially set to null");
|
||||
|
||||
// Check that enumerable, configurable, and has a getter and setter.
|
||||
const objDescriptor = Object.getOwnPropertyDescriptor(window, "oninstall");
|
||||
ok(objDescriptor.enumerable, "is enumerable");
|
||||
ok(objDescriptor.configurable, "is configurable");
|
||||
ok(objDescriptor.hasOwnProperty("get"), "has getter");
|
||||
ok(objDescriptor.hasOwnProperty("set"), "has setter");
|
||||
resolve(ifrWindow);
|
||||
});
|
||||
}
|
||||
|
||||
// Checks that .oninstall receives an event.
|
||||
function checkOnInstallEventFires(ifrWindow) {
|
||||
const customEv = new CustomEvent("install");
|
||||
return new Promise((resolve) => {
|
||||
// Test is we receive the event on `oninstall`
|
||||
ifrWindow.oninstall = ev => {
|
||||
ifrWindow.oninstall = null;
|
||||
is(ev, customEv, "The events should be the same event object");
|
||||
resolve(ifrWindow);
|
||||
};
|
||||
ifrWindow.dispatchEvent(customEv);
|
||||
});
|
||||
}
|
||||
|
||||
// Checks that .addEventListener("install") receives an event.
|
||||
function checkAddEventListenerFires(ifrWindow) {
|
||||
const customEv = new CustomEvent("install");
|
||||
return new Promise((resolve) => {
|
||||
ifrWindow.addEventListener("install", function handler(ev) {
|
||||
ifrWindow.removeEventListener("install", handler);
|
||||
is(ev, customEv, "The events should be the same");
|
||||
resolve(ifrWindow);
|
||||
});
|
||||
ifrWindow.dispatchEvent(customEv);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
@ -93,7 +93,8 @@ MP4Decoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs,
|
||||
// the web, as opposed to what we use internally (i.e. what our demuxers
|
||||
// etc output).
|
||||
const bool isMP4Audio = aMIMETypeExcludingCodecs.EqualsASCII("audio/mp4") ||
|
||||
aMIMETypeExcludingCodecs.EqualsASCII("audio/x-m4a");
|
||||
aMIMETypeExcludingCodecs.EqualsASCII("audio/x-m4a") ||
|
||||
aMIMETypeExcludingCodecs.EqualsASCII("audio/opus");
|
||||
const bool isMP4Video =
|
||||
// On B2G, treat 3GPP as MP4 when Gonk PDM is available.
|
||||
#ifdef MOZ_GONK_MEDIACODEC
|
||||
|
@ -5,6 +5,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "AgnosticDecoderModule.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "OpusDecoder.h"
|
||||
#include "VorbisDecoder.h"
|
||||
#include "VPXDecoder.h"
|
||||
@ -16,10 +17,14 @@ bool
|
||||
AgnosticDecoderModule::SupportsMimeType(const nsACString& aMimeType,
|
||||
DecoderDoctorDiagnostics* aDiagnostics) const
|
||||
{
|
||||
return VPXDecoder::IsVPX(aMimeType) ||
|
||||
bool supports =
|
||||
VPXDecoder::IsVPX(aMimeType) ||
|
||||
OpusDataDecoder::IsOpus(aMimeType) ||
|
||||
VorbisDataDecoder::IsVorbis(aMimeType) ||
|
||||
WaveDataDecoder::IsWave(aMimeType);
|
||||
MOZ_LOG(sPDMLog, LogLevel::Debug, ("Agnostic decoder %s requested type",
|
||||
supports ? "supports" : "rejects"));
|
||||
return supports;
|
||||
}
|
||||
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
|
@ -47,18 +47,28 @@ OpusDataDecoder::Shutdown()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
OpusDataDecoder::AppendCodecDelay(MediaByteBuffer* config, uint64_t codecDelayUS)
|
||||
{
|
||||
uint8_t buffer[sizeof(uint64_t)];
|
||||
BigEndian::writeUint64(buffer, codecDelayUS);
|
||||
config->AppendElements(buffer, sizeof(uint64_t));
|
||||
}
|
||||
|
||||
RefPtr<MediaDataDecoder::InitPromise>
|
||||
OpusDataDecoder::Init()
|
||||
{
|
||||
size_t length = mInfo.mCodecSpecificConfig->Length();
|
||||
uint8_t *p = mInfo.mCodecSpecificConfig->Elements();
|
||||
if (length < sizeof(uint64_t)) {
|
||||
OPUS_DEBUG("CodecSpecificConfig too short to read codecDelay!");
|
||||
return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
|
||||
}
|
||||
int64_t codecDelay = BigEndian::readUint64(p);
|
||||
length -= sizeof(uint64_t);
|
||||
p += sizeof(uint64_t);
|
||||
if (NS_FAILED(DecodeHeader(p, length))) {
|
||||
OPUS_DEBUG("Error decoding header!");
|
||||
return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
|
||||
}
|
||||
|
||||
@ -348,7 +358,9 @@ bool
|
||||
OpusDataDecoder::IsOpus(const nsACString& aMimeType)
|
||||
{
|
||||
return aMimeType.EqualsLiteral("audio/webm; codecs=opus") ||
|
||||
aMimeType.EqualsLiteral("audio/ogg; codecs=opus");
|
||||
aMimeType.EqualsLiteral("audio/ogg; codecs=opus") ||
|
||||
aMimeType.EqualsLiteral("audio/mp4; codecs=opus") ||
|
||||
aMimeType.EqualsLiteral("audio/opus");
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -33,6 +33,13 @@ public:
|
||||
// Return true if mimetype is Opus
|
||||
static bool IsOpus(const nsACString& aMimeType);
|
||||
|
||||
// Pack pre-skip/CodecDelay, given in microseconds, into a
|
||||
// MediaByteBuffer. The decoder expects this value to come
|
||||
// from the container (if any) and to precede the OpusHead
|
||||
// block in the CodecSpecificConfig buffer to verify the
|
||||
// values match.
|
||||
static void AppendCodecDelay(MediaByteBuffer* config, uint64_t codecDelayUS);
|
||||
|
||||
private:
|
||||
enum DecodeError {
|
||||
DECODE_SUCCESS,
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "AbstractMediaDecoder.h"
|
||||
#include "MediaResource.h"
|
||||
#include "OpusDecoder.h"
|
||||
#include "WebMDemuxer.h"
|
||||
#include "WebMBufferedParser.h"
|
||||
#include "gfx2DGlue.h"
|
||||
@ -396,15 +397,13 @@ WebMDemuxer::ReadMetadata()
|
||||
|
||||
mAudioTrack = track;
|
||||
mHasAudio = true;
|
||||
mCodecDelay = media::TimeUnit::FromNanoseconds(params.codec_delay).ToMicroseconds();
|
||||
mAudioCodec = nestegg_track_codec_id(context, track);
|
||||
if (mAudioCodec == NESTEGG_CODEC_VORBIS) {
|
||||
mInfo.mAudio.mMimeType = "audio/webm; codecs=vorbis";
|
||||
} else if (mAudioCodec == NESTEGG_CODEC_OPUS) {
|
||||
mInfo.mAudio.mMimeType = "audio/webm; codecs=opus";
|
||||
uint8_t c[sizeof(uint64_t)];
|
||||
BigEndian::writeUint64(&c[0], mCodecDelay);
|
||||
mInfo.mAudio.mCodecSpecificConfig->AppendElements(&c[0], sizeof(uint64_t));
|
||||
OpusDataDecoder::AppendCodecDelay(mInfo.mAudio.mCodecSpecificConfig,
|
||||
media::TimeUnit::FromNanoseconds(params.codec_delay).ToMicroseconds());
|
||||
}
|
||||
mSeekPreroll = params.seek_preroll;
|
||||
mInfo.mAudio.mRate = params.rate;
|
||||
|
@ -213,9 +213,6 @@ private:
|
||||
uint32_t mVideoTrack;
|
||||
uint32_t mAudioTrack;
|
||||
|
||||
// Number of microseconds that must be discarded from the start of the Stream.
|
||||
uint64_t mCodecDelay;
|
||||
|
||||
// Nanoseconds to discard after seeking.
|
||||
uint64_t mSeekPreroll;
|
||||
|
||||
|
@ -99,6 +99,18 @@ interface nsIPluginHost : nsISupports
|
||||
ACString getPermissionStringForType(in AUTF8String mimeType,
|
||||
[optional] in uint32_t excludeFlags);
|
||||
|
||||
/**
|
||||
* Get the "permission string" for the plugin. This is a string that can be
|
||||
* passed to the permission manager to see whether the plugin is allowed to
|
||||
* run, for example. This will typically be based on the plugin's "nice name"
|
||||
* and its blocklist state.
|
||||
*
|
||||
* @tag The tage we're interested in
|
||||
* @excludeFlags Set of the EXCLUDE_* flags above, defaulting to EXCLUDE_NONE.
|
||||
*/
|
||||
ACString getPermissionStringForTag(in nsIPluginTag tag,
|
||||
[optional] in uint32_t excludeFlags);
|
||||
|
||||
/**
|
||||
* Get the nsIPluginTag for this MIME type. This method works with both
|
||||
* enabled and disabled/blocklisted plugins, but an enabled plugin will
|
||||
|
@ -1110,11 +1110,19 @@ nsPluginHost::GetPermissionStringForType(const nsACString &aMimeType,
|
||||
nsresult rv = GetPluginTagForType(aMimeType, aExcludeFlags,
|
||||
getter_AddRefs(tag));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(tag, NS_ERROR_FAILURE);
|
||||
return GetPermissionStringForTag(tag, aExcludeFlags, aPermissionString);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPluginHost::GetPermissionStringForTag(nsIPluginTag* aTag,
|
||||
uint32_t aExcludeFlags,
|
||||
nsACString &aPermissionString)
|
||||
{
|
||||
NS_ENSURE_TRUE(aTag, NS_ERROR_FAILURE);
|
||||
|
||||
aPermissionString.Truncate();
|
||||
uint32_t blocklistState;
|
||||
rv = tag->GetBlocklistState(&blocklistState);
|
||||
nsresult rv = aTag->GetBlocklistState(&blocklistState);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (blocklistState == nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE ||
|
||||
@ -1126,7 +1134,7 @@ nsPluginHost::GetPermissionStringForType(const nsACString &aMimeType,
|
||||
}
|
||||
|
||||
nsCString niceName;
|
||||
rv = tag->GetNiceName(niceName);
|
||||
rv = aTag->GetNiceName(niceName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(!niceName.IsEmpty(), NS_ERROR_FAILURE);
|
||||
|
||||
|
@ -323,7 +323,7 @@ nsPluginTag::~nsPluginTag()
|
||||
NS_ASSERTION(!mNext, "Risk of exhausting the stack space, bug 486349");
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsPluginTag, nsIPluginTag, nsIInternalPluginTag)
|
||||
NS_IMPL_ISUPPORTS(nsPluginTag, nsPluginTag, nsIInternalPluginTag, nsIPluginTag)
|
||||
|
||||
void nsPluginTag::InitMime(const char* const* aMimeTypes,
|
||||
const char* const* aMimeDescriptions,
|
||||
|
@ -30,6 +30,9 @@ struct FakePluginTagInit;
|
||||
{ 0xe8fdd227, 0x27da, 0x46ee, \
|
||||
{ 0xbe, 0xf3, 0x1a, 0xef, 0x5a, 0x8f, 0xc5, 0xb4 } }
|
||||
|
||||
#define NS_PLUGINTAG_IID \
|
||||
{ 0xcce2e8b9, 0x9702, 0x4d4b, \
|
||||
{ 0xbe, 0xa4, 0x7c, 0x1e, 0x13, 0x1f, 0xaf, 0x78 } }
|
||||
class nsIInternalPluginTag : public nsIPluginTag
|
||||
{
|
||||
public:
|
||||
@ -90,6 +93,8 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIInternalPluginTag, NS_IINTERNALPLUGINTAG_IID)
|
||||
class nsPluginTag final : public nsIInternalPluginTag
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_PLUGINTAG_IID)
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIPLUGINTAG
|
||||
|
||||
@ -192,6 +197,7 @@ private:
|
||||
|
||||
static uint32_t sNextId;
|
||||
};
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsPluginTag, NS_PLUGINTAG_IID)
|
||||
|
||||
// A class representing "fake" plugin tags; that is plugin tags not
|
||||
// corresponding to actual NPAPI plugins. In practice these are all
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "mozilla/dom/CSPDictionariesBinding.h"
|
||||
#include "mozilla/net/ReferrerPolicy.h"
|
||||
#include "nsINetworkInterceptController.h"
|
||||
#include "nsSandboxFlags.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@ -1323,6 +1324,45 @@ nsCSPContext::ToJSON(nsAString& outCSPinJSON)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCSPContext::GetCSPSandboxFlags(uint32_t* aOutSandboxFlags)
|
||||
{
|
||||
if (!aOutSandboxFlags) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*aOutSandboxFlags = SANDBOXED_NONE;
|
||||
|
||||
for (uint32_t i = 0; i < mPolicies.Length(); i++) {
|
||||
uint32_t flags = mPolicies[i]->getSandboxFlags();
|
||||
|
||||
// current policy doesn't have sandbox flag, check next policy
|
||||
if (!flags) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// current policy has sandbox flags, if the policy is in enforcement-mode
|
||||
// (i.e. not report-only) set these flags and check for policies with more
|
||||
// restrictions
|
||||
if (!mPolicies[i]->getReportOnlyFlag()) {
|
||||
*aOutSandboxFlags |= flags;
|
||||
} else {
|
||||
// sandbox directive is ignored in report-only mode, warn about it and
|
||||
// continue the loop checking for an enforcement policy.
|
||||
nsAutoString policy;
|
||||
mPolicies[i]->toString(policy);
|
||||
|
||||
CSPCONTEXTLOG(("nsCSPContext::GetCSPSandboxFlags, report only policy, ignoring sandbox in: %s",
|
||||
policy.get()));
|
||||
|
||||
const char16_t* params[] = { policy.get() };
|
||||
logToConsole(MOZ_UTF16("ignoringReportOnlyDirective"), params, ArrayLength(params),
|
||||
EmptyString(), EmptyString(), 0, 0, nsIScriptError::warningFlag);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* ========== CSPViolationReportListener implementation ========== */
|
||||
|
||||
NS_IMPL_ISUPPORTS(CSPViolationReportListener, nsIStreamListener, nsIRequestObserver, nsISupports);
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCSPParser.h"
|
||||
#include "nsCSPUtils.h"
|
||||
#include "nsIConsoleService.h"
|
||||
@ -993,6 +994,41 @@ nsCSPParser::reportURIList(nsTArray<nsCSPBaseSrc*>& outSrcs)
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper function for parsing sandbox flags. This function solely concatenates
|
||||
* all the source list tokens (the sandbox flags) so the attribute parser
|
||||
* (nsContentUtils::ParseSandboxAttributeToFlags) can parse them.
|
||||
*/
|
||||
void
|
||||
nsCSPParser::sandboxFlagList(nsTArray<nsCSPBaseSrc*>& outSrcs)
|
||||
{
|
||||
nsAutoString flags;
|
||||
|
||||
// remember, srcs start at index 1
|
||||
for (uint32_t i = 1; i < mCurDir.Length(); i++) {
|
||||
mCurToken = mCurDir[i];
|
||||
|
||||
CSPPARSERLOG(("nsCSPParser::sandboxFlagList, mCurToken: %s, mCurValue: %s",
|
||||
NS_ConvertUTF16toUTF8(mCurToken).get(),
|
||||
NS_ConvertUTF16toUTF8(mCurValue).get()));
|
||||
|
||||
if (!nsContentUtils::IsValidSandboxFlag(mCurToken)) {
|
||||
const char16_t* params[] = { mCurToken.get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag,
|
||||
"couldntParseInvalidSandboxFlag",
|
||||
params, ArrayLength(params));
|
||||
continue;
|
||||
}
|
||||
|
||||
flags.Append(mCurToken);
|
||||
if (i != mCurDir.Length() - 1) {
|
||||
flags.AppendASCII(" ");
|
||||
}
|
||||
}
|
||||
|
||||
nsCSPSandboxFlags* sandboxFlags = new nsCSPSandboxFlags(flags);
|
||||
outSrcs.AppendElement(sandboxFlags);
|
||||
}
|
||||
|
||||
// directive-value = *( WSP / <VCHAR except ";" and ","> )
|
||||
void
|
||||
nsCSPParser::directiveValue(nsTArray<nsCSPBaseSrc*>& outSrcs)
|
||||
@ -1014,6 +1050,13 @@ nsCSPParser::directiveValue(nsTArray<nsCSPBaseSrc*>& outSrcs)
|
||||
return;
|
||||
}
|
||||
|
||||
// For the sandbox flag the source list is a list of flags, so we're special
|
||||
// casing this directive
|
||||
if (CSP_IsDirective(mCurDir[0], nsIContentSecurityPolicy::SANDBOX_DIRECTIVE)) {
|
||||
sandboxFlagList(outSrcs);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise just forward to sourceList
|
||||
sourceList(outSrcs);
|
||||
}
|
||||
@ -1061,7 +1104,8 @@ nsCSPParser::directiveName()
|
||||
// http://www.w3.org/TR/CSP11/#delivery-html-meta-element
|
||||
if (mDeliveredViaMetaTag &&
|
||||
((CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::REPORT_URI_DIRECTIVE)) ||
|
||||
(CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE)))) {
|
||||
(CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE)) ||
|
||||
(CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::SANDBOX_DIRECTIVE)))) {
|
||||
// log to the console to indicate that meta CSP is ignoring the directive
|
||||
const char16_t* params[] = { mCurToken.get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag,
|
||||
|
@ -137,14 +137,15 @@ class nsCSPParser {
|
||||
bool port();
|
||||
bool path(nsCSPHostSrc* aCspHost);
|
||||
|
||||
bool subHost(); // helper function to parse subDomains
|
||||
bool atValidUnreservedChar(); // helper function to parse unreserved
|
||||
bool atValidSubDelimChar(); // helper function to parse sub-delims
|
||||
bool atValidPctEncodedChar(); // helper function to parse pct-encoded
|
||||
bool subPath(nsCSPHostSrc* aCspHost); // helper function to parse paths
|
||||
void reportURIList(nsTArray<nsCSPBaseSrc*>& outSrcs); // helper function to parse report-uris
|
||||
void percentDecodeStr(const nsAString& aEncStr, // helper function to percent-decode
|
||||
bool subHost(); // helper function to parse subDomains
|
||||
bool atValidUnreservedChar(); // helper function to parse unreserved
|
||||
bool atValidSubDelimChar(); // helper function to parse sub-delims
|
||||
bool atValidPctEncodedChar(); // helper function to parse pct-encoded
|
||||
bool subPath(nsCSPHostSrc* aCspHost); // helper function to parse paths
|
||||
void reportURIList(nsTArray<nsCSPBaseSrc*>& outSrcs); // helper function to parse report-uris
|
||||
void percentDecodeStr(const nsAString& aEncStr, // helper function to percent-decode
|
||||
nsAString& outDecStr);
|
||||
void sandboxFlagList(nsTArray<nsCSPBaseSrc*>& outSrcs); // helper function to parse sandbox flags
|
||||
|
||||
inline bool atEnd()
|
||||
{
|
||||
|
@ -4,6 +4,8 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsAttrValue.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCSPUtils.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsIConsoleService.h"
|
||||
@ -13,6 +15,7 @@
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsSandboxFlags.h"
|
||||
|
||||
static mozilla::LogModule*
|
||||
GetCspUtilsLog()
|
||||
@ -792,6 +795,29 @@ nsCSPReportURI::toString(nsAString& outStr) const
|
||||
outStr.AppendASCII(spec.get());
|
||||
}
|
||||
|
||||
/* ===== nsCSPSandboxFlags ===================== */
|
||||
|
||||
nsCSPSandboxFlags::nsCSPSandboxFlags(const nsAString& aFlags)
|
||||
: mFlags(aFlags)
|
||||
{
|
||||
}
|
||||
|
||||
nsCSPSandboxFlags::~nsCSPSandboxFlags()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
nsCSPSandboxFlags::visit(nsCSPSrcVisitor* aVisitor) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
nsCSPSandboxFlags::toString(nsAString& outStr) const
|
||||
{
|
||||
outStr.Append(mFlags);
|
||||
}
|
||||
|
||||
/* ===== nsCSPDirective ====================== */
|
||||
|
||||
nsCSPDirective::nsCSPDirective(CSPDirective aDirective)
|
||||
@ -953,6 +979,11 @@ nsCSPDirective::toDomCSPStruct(mozilla::dom::CSP& outCSP) const
|
||||
outCSP.mChild_src.Value() = mozilla::Move(srcs);
|
||||
return;
|
||||
|
||||
case nsIContentSecurityPolicy::SANDBOX_DIRECTIVE:
|
||||
outCSP.mSandbox.Construct();
|
||||
outCSP.mSandbox.Value() = mozilla::Move(srcs);
|
||||
return;
|
||||
|
||||
// REFERRER_DIRECTIVE and REQUIRE_SRI_FOR are handled in nsCSPPolicy::toDomCSPStruct()
|
||||
|
||||
default:
|
||||
@ -1344,6 +1375,33 @@ nsCSPPolicy::getDirectiveAsString(CSPDirective aDir, nsAString& outDirective) co
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function that returns the underlying bit representation of sandbox
|
||||
* flags. The function returns SANDBOXED_NONE if there are no sandbox
|
||||
* directives.
|
||||
*/
|
||||
uint32_t
|
||||
nsCSPPolicy::getSandboxFlags() const
|
||||
{
|
||||
for (uint32_t i = 0; i < mDirectives.Length(); i++) {
|
||||
if (mDirectives[i]->equals(nsIContentSecurityPolicy::SANDBOX_DIRECTIVE)) {
|
||||
nsAutoString flags;
|
||||
mDirectives[i]->toString(flags);
|
||||
|
||||
if (flags.IsEmpty()) {
|
||||
return SANDBOX_ALL_FLAGS;
|
||||
}
|
||||
|
||||
nsAttrValue attr;
|
||||
attr.ParseAtomArray(flags);
|
||||
|
||||
return nsContentUtils::ParseSandboxAttributeToFlags(&attr);
|
||||
}
|
||||
}
|
||||
|
||||
return SANDBOXED_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
nsCSPPolicy::getReportURIs(nsTArray<nsString>& outReportURIs) const
|
||||
{
|
||||
|
@ -92,8 +92,8 @@ static const char* CSPStrDirectives[] = {
|
||||
"upgrade-insecure-requests", // UPGRADE_IF_INSECURE_DIRECTIVE
|
||||
"child-src", // CHILD_SRC_DIRECTIVE
|
||||
"block-all-mixed-content", // BLOCK_ALL_MIXED_CONTENT
|
||||
"require-sri-for" // REQUIRE_SRI_FOR
|
||||
|
||||
"require-sri-for", // REQUIRE_SRI_FOR
|
||||
"sandbox" // SANDBOX_DIRECTIVE
|
||||
};
|
||||
|
||||
inline const char* CSP_CSPDirectiveToString(CSPDirective aDir)
|
||||
@ -334,6 +334,20 @@ class nsCSPReportURI : public nsCSPBaseSrc {
|
||||
nsCOMPtr<nsIURI> mReportURI;
|
||||
};
|
||||
|
||||
/* =============== nsCSPSandboxFlags ================== */
|
||||
|
||||
class nsCSPSandboxFlags : public nsCSPBaseSrc {
|
||||
public:
|
||||
explicit nsCSPSandboxFlags(const nsAString& aFlags);
|
||||
virtual ~nsCSPSandboxFlags();
|
||||
|
||||
bool visit(nsCSPSrcVisitor* aVisitor) const;
|
||||
void toString(nsAString& outStr) const;
|
||||
|
||||
private:
|
||||
nsString mFlags;
|
||||
};
|
||||
|
||||
/* =============== nsCSPSrcVisitor ================== */
|
||||
|
||||
class nsCSPSrcVisitor {
|
||||
@ -558,6 +572,8 @@ class nsCSPPolicy {
|
||||
|
||||
void getDirectiveAsString(CSPDirective aDir, nsAString& outDirective) const;
|
||||
|
||||
uint32_t getSandboxFlags() const;
|
||||
|
||||
bool requireSRIForType(nsContentPolicyType aContentType);
|
||||
|
||||
inline uint32_t getNumDirectives() const
|
||||
|
@ -175,6 +175,13 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
|
||||
nsCString mimeTypeGuess;
|
||||
nsCOMPtr<nsINode> requestingContext = nullptr;
|
||||
|
||||
#ifdef DEBUG
|
||||
// Don't enforce TYPE_DOCUMENT assertions for loads
|
||||
// initiated by javascript tests.
|
||||
bool skipContentTypeCheck = false;
|
||||
skipContentTypeCheck = Preferences::GetBool("network.loadinfo.skip_type_assertion");
|
||||
#endif
|
||||
|
||||
switch(contentPolicyType) {
|
||||
case nsIContentPolicy::TYPE_OTHER: {
|
||||
mimeTypeGuess = EmptyCString();
|
||||
@ -207,7 +214,7 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
|
||||
}
|
||||
|
||||
case nsIContentPolicy::TYPE_DOCUMENT: {
|
||||
MOZ_ASSERT(false, "contentPolicyType not supported yet");
|
||||
MOZ_ASSERT(skipContentTypeCheck || false, "contentPolicyType not supported yet");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<script type="text/javascript">
|
||||
function ok(result, desc) {
|
||||
window.parent.postMessage({ok: result, desc: desc}, "*");
|
||||
}
|
||||
function doStuff() {
|
||||
var beforePrincipal = SpecialPowers.wrap(document).nodePrincipal;
|
||||
document.open();
|
||||
document.write("rewritten sandboxed document");
|
||||
document.close();
|
||||
var afterPrincipal = SpecialPowers.wrap(document).nodePrincipal;
|
||||
ok(beforePrincipal.equals(afterPrincipal),
|
||||
"document.write() does not change underlying principal");
|
||||
}
|
||||
</script>
|
||||
<body onLoad='doStuff();'>
|
||||
sandboxed with allow-scripts
|
||||
</body>
|
||||
</html>
|
16
dom/security/test/csp/file_sandbox_1.html
Normal file
16
dom/security/test/csp/file_sandbox_1.html
Normal file
@ -0,0 +1,16 @@
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<body>
|
||||
<!-- sandbox="allow-same-origin" -->
|
||||
<!-- Content-Security-Policy: default-src 'self' -->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img1_bad&type=img/png"> </img>
|
||||
|
||||
<!-- these should load ok -->
|
||||
<img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img1a_good&type=img/png" />
|
||||
<!-- should not execute script -->
|
||||
<script src='/tests/dom/security/test/csp/file_sandbox_fail.js'></script>
|
||||
|
||||
</body>
|
||||
</html>
|
12
dom/security/test/csp/file_sandbox_10.html
Normal file
12
dom/security/test/csp/file_sandbox_10.html
Normal file
@ -0,0 +1,12 @@
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<body>
|
||||
<!-- Content-Security-Policy: default-src 'none'; sandbox -->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img10_bad&type=img/png"> </img>
|
||||
<img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img10a_bad&type=img/png" />
|
||||
<script src='/tests/dom/security/test/csp/file_sandbox_fail.js'></script>
|
||||
|
||||
</body>
|
||||
</html>
|
25
dom/security/test/csp/file_sandbox_11.html
Normal file
25
dom/security/test/csp/file_sandbox_11.html
Normal file
@ -0,0 +1,25 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<script type="text/javascript">
|
||||
function ok(result, desc) {
|
||||
window.parent.postMessage({ok: result, desc: desc}, "*");
|
||||
}
|
||||
|
||||
function doStuff() {
|
||||
ok(true, "documents sandboxed with allow-scripts should be able to run inline scripts");
|
||||
}
|
||||
</script>
|
||||
<script src='file_sandbox_fail.js'></script>
|
||||
<body onLoad='ok(true, "documents sandboxed with allow-scripts should be able to run script from event listeners");doStuff();'>
|
||||
I am sandboxed but with only inline "allow-scripts"
|
||||
|
||||
<!-- Content-Security-Policy: default-src 'none'; script-src 'unsafe-inline'; sandbox allow-scripts -->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img11_bad&type=img/png" />
|
||||
<img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img11a_bad&type=img/png"> </img>
|
||||
<script src='/tests/dom/security/test/csp/file_CSP.sjs?testid=script11_bad&type=text/javascript'></script>
|
||||
<script src='http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=script11a_bad&type=text/javascript'></script>
|
||||
</body>
|
||||
</html>
|
40
dom/security/test/csp/file_sandbox_12.html
Normal file
40
dom/security/test/csp/file_sandbox_12.html
Normal file
@ -0,0 +1,40 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
</head>
|
||||
<script type="text/javascript">
|
||||
function ok(result, desc) {
|
||||
window.parent.postMessage({ok: result, desc: desc}, "*");
|
||||
}
|
||||
|
||||
function doStuff() {
|
||||
ok(true, "documents sandboxed with allow-scripts should be able to run inline scripts");
|
||||
|
||||
document.getElementById('a_form').submit();
|
||||
|
||||
// trigger the javascript: url test
|
||||
sendMouseEvent({type:'click'}, 'a_link');
|
||||
}
|
||||
</script>
|
||||
<script src='file_sandbox_pass.js'></script>
|
||||
<body onLoad='ok(true, "documents sandboxed with allow-scripts should be able to run script from event listeners");doStuff();'>
|
||||
I am sandboxed but with "allow-same-origin" and allow-scripts"
|
||||
|
||||
|
||||
<!-- Content-Security-Policy: sandbox allow-same-origin allow-scripts; default-src 'self' 'unsafe-inline'; -->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img12_bad&type=img/png"> </img>
|
||||
<script src='http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=script12_bad&type=text/javascript'></script>
|
||||
|
||||
<form method="get" action="/tests/content/html/content/test/file_iframe_sandbox_form_fail.html" id="a_form">
|
||||
First name: <input type="text" name="firstname">
|
||||
Last name: <input type="text" name="lastname">
|
||||
<input type="submit" onclick="doSubmit()" id="a_button">
|
||||
</form>
|
||||
|
||||
<a href = 'javascript:ok(true, "documents sandboxed with allow-scripts should be able to run script from javascript: URLs");' id='a_link'>click me</a>
|
||||
</body>
|
||||
</html>
|
16
dom/security/test/csp/file_sandbox_2.html
Normal file
16
dom/security/test/csp/file_sandbox_2.html
Normal file
@ -0,0 +1,16 @@
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<body>
|
||||
<!-- sandbox -->
|
||||
<!-- Content-Security-Policy: default-src 'self' -->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img2_bad&type=img/png"> </img>
|
||||
|
||||
<!-- these should load ok -->
|
||||
<img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img2a_good&type=img/png" />
|
||||
<!-- should not execute script -->
|
||||
<script src='/tests/dom/security/test/csp/file_sandbox_fail.js'></script>
|
||||
|
||||
</body>
|
||||
</html>
|
13
dom/security/test/csp/file_sandbox_3.html
Normal file
13
dom/security/test/csp/file_sandbox_3.html
Normal file
@ -0,0 +1,13 @@
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<body>
|
||||
<!-- sandbox="allow-same-origin" -->
|
||||
<!-- Content-Security-Policy: default-src 'none' -->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img3_bad&type=img/png"> </img>
|
||||
<img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img3a_bad&type=img/png" />
|
||||
<script src='/tests/dom/security/test/csp/file_sandbox_fail.js'></script>
|
||||
|
||||
</body>
|
||||
</html>
|
13
dom/security/test/csp/file_sandbox_4.html
Normal file
13
dom/security/test/csp/file_sandbox_4.html
Normal file
@ -0,0 +1,13 @@
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<body>
|
||||
<!-- sandbox -->
|
||||
<!-- Content-Security-Policy: default-src 'none' -->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="http://example.org/tests/dom/base/test/csp/file_CSP.sjs?testid=img4_bad&type=img/png"> </img>
|
||||
<img src="/tests/dom/base/test/csp/file_CSP.sjs?testid=img4a_bad&type=img/png" />
|
||||
<script src='/tests/dom/base/test/csp/file_sandbox_fail.js'></script>
|
||||
|
||||
</body>
|
||||
</html>
|
26
dom/security/test/csp/file_sandbox_5.html
Normal file
26
dom/security/test/csp/file_sandbox_5.html
Normal file
@ -0,0 +1,26 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<script type="text/javascript">
|
||||
function ok(result, desc) {
|
||||
window.parent.postMessage({ok: result, desc: desc}, "*");
|
||||
}
|
||||
|
||||
function doStuff() {
|
||||
ok(true, "documents sandboxed with allow-scripts should be able to run inline scripts");
|
||||
}
|
||||
</script>
|
||||
<script src='file_sandbox_fail.js'></script>
|
||||
<body onLoad='ok(true, "documents sandboxed with allow-scripts should be able to run script from event listeners");doStuff();'>
|
||||
I am sandboxed but with only inline "allow-scripts"
|
||||
|
||||
<!-- sandbox="allow-scripts" -->
|
||||
<!-- Content-Security-Policy: default-src 'none'; script-src 'unsafe-inline' -->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img5_bad&type=img/png" />
|
||||
<img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img5a_bad&type=img/png"> </img>
|
||||
<script src='/tests/dom/security/test/csp/file_CSP.sjs?testid=script5_bad&type=text/javascript'></script>
|
||||
<script src='http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=script5a_bad&type=text/javascript'></script>
|
||||
</body>
|
||||
</html>
|
35
dom/security/test/csp/file_sandbox_6.html
Normal file
35
dom/security/test/csp/file_sandbox_6.html
Normal file
@ -0,0 +1,35 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
</head>
|
||||
<script type="text/javascript">
|
||||
function ok(result, desc) {
|
||||
window.parent.postMessage({ok: result, desc: desc}, "*");
|
||||
}
|
||||
|
||||
function doStuff() {
|
||||
ok(true, "documents sandboxed with allow-scripts should be able to run inline scripts");
|
||||
|
||||
document.getElementById('a_form').submit();
|
||||
|
||||
// trigger the javascript: url test
|
||||
sendMouseEvent({type:'click'}, 'a_link');
|
||||
}
|
||||
</script>
|
||||
<script src='file_sandbox_pass.js'></script>
|
||||
<body onLoad='ok(true, "documents sandboxed with allow-scripts should be able to run script from event listeners");doStuff();'>
|
||||
I am sandboxed but with "allow-same-origin" and allow-scripts"
|
||||
<img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img6_bad&type=img/png"> </img>
|
||||
<script src='http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=script6_bad&type=text/javascript'></script>
|
||||
|
||||
<form method="get" action="/tests/content/html/content/test/file_iframe_sandbox_form_fail.html" id="a_form">
|
||||
First name: <input type="text" name="firstname">
|
||||
Last name: <input type="text" name="lastname">
|
||||
<input type="submit" onclick="doSubmit()" id="a_button">
|
||||
</form>
|
||||
|
||||
<a href = 'javascript:ok(true, "documents sandboxed with allow-scripts should be able to run script from javascript: URLs");' id='a_link'>click me</a>
|
||||
</body>
|
||||
</html>
|
15
dom/security/test/csp/file_sandbox_7.html
Normal file
15
dom/security/test/csp/file_sandbox_7.html
Normal file
@ -0,0 +1,15 @@
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<body>
|
||||
<!-- Content-Security-Policy: default-src 'self'; sandbox allow-same-origin -->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img7_bad&type=img/png"> </img>
|
||||
|
||||
<!-- these should load ok -->
|
||||
<img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img7a_good&type=img/png" />
|
||||
<!-- should not execute script -->
|
||||
<script src='/tests/dom/security/test/csp/file_sandbox_fail.js'></script>
|
||||
|
||||
</body>
|
||||
</html>
|
15
dom/security/test/csp/file_sandbox_8.html
Normal file
15
dom/security/test/csp/file_sandbox_8.html
Normal file
@ -0,0 +1,15 @@
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<body>
|
||||
<!-- Content-Security-Policy: sandbox; default-src 'self' -->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img8_bad&type=img/png"> </img>
|
||||
|
||||
<!-- these should load ok -->
|
||||
<img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img8a_good&type=img/png" />
|
||||
<!-- should not execute script -->
|
||||
<script src='/tests/dom/security/test/csp/file_sandbox_fail.js'></script>
|
||||
|
||||
</body>
|
||||
</html>
|
12
dom/security/test/csp/file_sandbox_9.html
Normal file
12
dom/security/test/csp/file_sandbox_9.html
Normal file
@ -0,0 +1,12 @@
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<body>
|
||||
<!-- Content-Security-Policy: default-src 'none'; sandbox allow-same-origin -->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img9_bad&type=img/png"> </img>
|
||||
<img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img9a_bad&type=img/png" />
|
||||
|
||||
<script src='/tests/dom/security/test/csp/file_sandbox_fail.js'></script>
|
||||
</body>
|
||||
</html>
|
4
dom/security/test/csp/file_sandbox_fail.js
Normal file
4
dom/security/test/csp/file_sandbox_fail.js
Normal file
@ -0,0 +1,4 @@
|
||||
function ok(result, desc) {
|
||||
window.parent.postMessage({ok: result, desc: desc}, "*");
|
||||
}
|
||||
ok(false, "documents sandboxed with allow-scripts should NOT be able to run <script src=...>");
|
4
dom/security/test/csp/file_sandbox_pass.js
Normal file
4
dom/security/test/csp/file_sandbox_pass.js
Normal file
@ -0,0 +1,4 @@
|
||||
function ok(result, desc) {
|
||||
window.parent.postMessage({ok: result, desc: desc}, "*");
|
||||
}
|
||||
ok(true, "documents sandboxed with allow-scripts should be able to run <script src=...>");
|
@ -39,6 +39,11 @@ function handleRequest(request, response) {
|
||||
response.setHeader("Content-Security-Policy", query.get("csp"), false);
|
||||
}
|
||||
|
||||
// Deliver the CSP report-only policy encoded in the URI
|
||||
if(query.has("cspRO")){
|
||||
response.setHeader("Content-Security-Policy-Report-Only", query.get("cspRO"), false);
|
||||
}
|
||||
|
||||
// Deliver the CORS header in the URL
|
||||
if(query.has("cors")){
|
||||
response.setHeader("Access-Control-Allow-Origin", query.get("cors"), false);
|
||||
@ -46,5 +51,7 @@ function handleRequest(request, response) {
|
||||
|
||||
// Send HTML to test allowed/blocked behaviors
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
response.write(loadHTMLFromFile(query.get("file")));
|
||||
if(query.has("file")){
|
||||
response.write(loadHTMLFromFile(query.get("file")));
|
||||
}
|
||||
}
|
||||
|
@ -163,6 +163,22 @@ support-files =
|
||||
!/image/test/mochitest/blue.png
|
||||
file_meta_whitespace_skipping.html
|
||||
file_ping.html
|
||||
test_iframe_sandbox_top_1.html^headers^
|
||||
file_iframe_sandbox_document_write.html
|
||||
file_sandbox_pass.js
|
||||
file_sandbox_fail.js
|
||||
file_sandbox_1.html
|
||||
file_sandbox_2.html
|
||||
file_sandbox_3.html
|
||||
file_sandbox_4.html
|
||||
file_sandbox_5.html
|
||||
file_sandbox_6.html
|
||||
file_sandbox_7.html
|
||||
file_sandbox_8.html
|
||||
file_sandbox_9.html
|
||||
file_sandbox_10.html
|
||||
file_sandbox_11.html
|
||||
file_sandbox_12.html
|
||||
|
||||
[test_base-uri.html]
|
||||
[test_blob_data_schemes.html]
|
||||
@ -249,4 +265,7 @@ tags = mcb
|
||||
tags = mcb
|
||||
[test_form_action_blocks_url.html]
|
||||
[test_meta_whitespace_skipping.html]
|
||||
[test_iframe_sandbox.html]
|
||||
[test_iframe_sandbox_top_1.html]
|
||||
[test_sandbox.html]
|
||||
[test_ping.html]
|
||||
|
239
dom/security/test/csp/test_iframe_sandbox.html
Normal file
239
dom/security/test/csp/test_iframe_sandbox.html
Normal file
@ -0,0 +1,239 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=671389
|
||||
Bug 671389 - Implement CSP sandbox directive
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Tests for Bug 671389</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<script type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// Check if two sandbox flags are the same, ignoring case-sensitivity.
|
||||
// getSandboxFlags returns a list of sandbox flags (if any) or
|
||||
// null if the flag is not set.
|
||||
// This function checks if two flags are the same, i.e., they're
|
||||
// either not set or have the same flags.
|
||||
function eqFlags(a, b) {
|
||||
if (a === null && b === null) { return true; }
|
||||
if (a === null || b === null) { return false; }
|
||||
if (a.length !== b.length) { return false; }
|
||||
var a_sorted = a.map(function(e) { return e.toLowerCase(); }).sort();
|
||||
var b_sorted = b.map(function(e) { return e.toLowerCase(); }).sort();
|
||||
for (var i in a_sorted) {
|
||||
if (a_sorted[i] !== b_sorted[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the sandbox flags of document doc.
|
||||
// If the flag is not set sandboxFlagsAsString returns null,
|
||||
// this function also returns null.
|
||||
// If the flag is set it may have some flags; in this case
|
||||
// this function returns the (potentially empty) list of flags.
|
||||
function getSandboxFlags(doc) {
|
||||
var flags = doc.sandboxFlagsAsString;
|
||||
if (flags === null) { return null; }
|
||||
return flags? flags.split(" "):[];
|
||||
}
|
||||
|
||||
// Constructor for a CSP sandbox flags test. The constructor
|
||||
// expectes a description 'desc' and set of options 'opts':
|
||||
// - sandboxAttribute: [null] or string corresponding to the iframe sandbox attributes
|
||||
// - csp: [null] or string corresponding to the CSP sandbox flags
|
||||
// - cspReportOnly: [null] or string corresponding to the CSP report-only sandbox flags
|
||||
// - file: [null] or string corresponding to file the server should serve
|
||||
// Above, we use [brackets] to denote default values.
|
||||
function CSPFlagsTest(desc, opts) {
|
||||
function ifundef(x, v) {
|
||||
return (x !== undefined) ? x : v;
|
||||
}
|
||||
|
||||
function intersect(as, bs) { // Intersect two csp attributes:
|
||||
as = as === null ? null
|
||||
: as.split(' ').filter(function(x) { return !!x; });
|
||||
bs = bs === null ? null
|
||||
: bs.split(' ').filter(function(x) { return !!x; });
|
||||
|
||||
if (as === null) { return bs; }
|
||||
if (bs === null) { return as; }
|
||||
|
||||
var cs = [];
|
||||
as.forEach(function(a) {
|
||||
if (a && bs.indexOf(a) != -1)
|
||||
cs.push(a);
|
||||
});
|
||||
return cs;
|
||||
}
|
||||
|
||||
this.desc = desc || "Untitled test";
|
||||
this.attr = ifundef(opts.sandboxAttribute, null);
|
||||
this.csp = ifundef(opts.csp, null);
|
||||
this.cspRO = ifundef(opts.cspReportOnly, null);
|
||||
this.file = ifundef(opts.file, null);
|
||||
this.expected = intersect(this.attr, this.csp);
|
||||
}
|
||||
|
||||
// Return function that checks that the actual flags are the same as the
|
||||
// expected flags
|
||||
CSPFlagsTest.prototype.checkFlags = function(iframe) {
|
||||
var this_ = this;
|
||||
return function() {
|
||||
try {
|
||||
var actual = getSandboxFlags(SpecialPowers.wrap(iframe).contentDocument);
|
||||
ok(eqFlags(actual, this_.expected),
|
||||
this_.desc, 'expected: "' + this_.expected + '", got: "' + actual + '"');
|
||||
} catch (e) {
|
||||
ok(false, this_.desc, 'expected: "' + this_.expected + '", failed with: "' + e + '"');
|
||||
}
|
||||
runNextTest();
|
||||
};
|
||||
};
|
||||
|
||||
// Set the iframe src and sandbox attribute
|
||||
CSPFlagsTest.prototype.runTest = function () {
|
||||
var iframe = document.createElement('iframe');
|
||||
document.getElementById("content").appendChild(iframe);
|
||||
iframe.onload = this.checkFlags(iframe);
|
||||
|
||||
// set sandbox attribute
|
||||
if (this.attr === null) {
|
||||
iframe.removeAttribute('sandbox');
|
||||
} else {
|
||||
iframe.sandbox = this.attr;
|
||||
}
|
||||
|
||||
// set query string
|
||||
var src = 'http://mochi.test:8888/tests/dom/security/test/csp/file_testserver.sjs';
|
||||
|
||||
var delim = '?';
|
||||
|
||||
if (this.csp !== null) {
|
||||
src += delim + 'csp=' + escape('sandbox ' + this.csp);
|
||||
delim = '&';
|
||||
}
|
||||
|
||||
if (this.cspRO !== null) {
|
||||
src += delim + 'cspRO=' + escape('sandbox ' + this.cspRO);
|
||||
delim = '&';
|
||||
}
|
||||
|
||||
if (this.file !== null) {
|
||||
src += delim + 'file=' + escape(this.file);
|
||||
delim = '&';
|
||||
}
|
||||
|
||||
iframe.src = src;
|
||||
iframe.width = iframe.height = 10;
|
||||
|
||||
}
|
||||
|
||||
testCases = [
|
||||
{
|
||||
desc: "Test 1: Header should not override attribute",
|
||||
sandboxAttribute: "",
|
||||
csp: "allow-forms aLLOw-POinter-lock alLOW-popups aLLOW-SAME-ORIGin ALLOW-SCRIPTS allow-top-navigation"
|
||||
},
|
||||
{
|
||||
desc: "Test 2: Attribute should not override header",
|
||||
sandboxAttribute: "sandbox allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-top-navigation",
|
||||
csp: ""
|
||||
},
|
||||
{
|
||||
desc: "Test 3: Header and attribute intersect",
|
||||
sandboxAttribute: "allow-same-origin allow-scripts",
|
||||
csp: "allow-forms allow-same-origin allow-scripts"
|
||||
},
|
||||
{
|
||||
desc: "Test 4: CSP sandbox sets the right flags (pt 1)",
|
||||
csp: "alLOW-FORms ALLOW-pointer-lock allow-popups allow-same-origin allow-scripts ALLOW-TOP-NAVIGation"
|
||||
},
|
||||
{
|
||||
desc: "Test 5: CSP sandbox sets the right flags (pt 2)",
|
||||
csp: "allow-same-origin allow-TOP-navigation"
|
||||
},
|
||||
{
|
||||
desc: "Test 6: CSP sandbox sets the right flags (pt 3)",
|
||||
csp: "allow-FORMS ALLOW-scripts"
|
||||
},
|
||||
{
|
||||
desc: "Test 7: CSP sandbox sets the right flags (pt 4)",
|
||||
csp: ""
|
||||
},
|
||||
{
|
||||
desc: "Test 8: CSP sandbox sets the right flags (pt 5)",
|
||||
csp: null
|
||||
},
|
||||
{
|
||||
desc: "Test 9: Read-only header should not override attribute",
|
||||
sandboxAttribute: "",
|
||||
cspReportOnly: "allow-forms ALLOW-pointer-lock allow-POPUPS allow-same-origin ALLOW-scripts allow-top-NAVIGATION"
|
||||
},
|
||||
{
|
||||
desc: "Test 10: Read-only header should not override CSP header",
|
||||
csp: "allow-forms allow-scripts",
|
||||
cspReportOnly: "allow-forms aLlOw-PoInTeR-lOcK aLLow-pOPupS aLLoW-SaME-oRIgIN alLow-scripts allow-tOp-navigation"
|
||||
},
|
||||
{
|
||||
desc: "Test 11: Read-only header should not override attribute or CSP header",
|
||||
sandboxAttribute: "allow-same-origin allow-scripts",
|
||||
csp: "allow-forms allow-same-origin allow-scripts",
|
||||
cspReportOnly: "allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-top-navigation"
|
||||
},
|
||||
{
|
||||
desc: "Test 12: CSP sandbox not affected by document.write()",
|
||||
csp: "allow-scripts",
|
||||
file: 'tests/dom/security/test/csp/file_iframe_sandbox_document_write.html'
|
||||
},
|
||||
].map(function(t) { return (new CSPFlagsTest(t.desc,t)); });
|
||||
|
||||
|
||||
var testCaseIndex = 0;
|
||||
|
||||
// Track ok messages from iframes
|
||||
var childMessages = 0;
|
||||
var totalChildMessages = 1;
|
||||
|
||||
|
||||
// Check to see if we ran all the tests and received all messges
|
||||
// from child iframes. If so, finish.
|
||||
function tryFinish() {
|
||||
if (testCaseIndex === testCases.length && childMessages === totalChildMessages){
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
function runNextTest() {
|
||||
|
||||
tryFinish();
|
||||
|
||||
if (testCaseIndex < testCases.length) {
|
||||
testCases[testCaseIndex].runTest();
|
||||
testCaseIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
function receiveMessage(event) {
|
||||
ok(event.data.ok, event.data.desc);
|
||||
childMessages++;
|
||||
tryFinish();
|
||||
}
|
||||
|
||||
window.addEventListener("message", receiveMessage, false);
|
||||
|
||||
addLoadEvent(runNextTest);
|
||||
</script>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=671389">Mozilla Bug 671389</a> - Implement CSP sandbox directive
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
80
dom/security/test/csp/test_iframe_sandbox_top_1.html
Normal file
80
dom/security/test/csp/test_iframe_sandbox_top_1.html
Normal file
@ -0,0 +1,80 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=671389
|
||||
Bug 671389 - Implement CSP sandbox directive
|
||||
|
||||
Tests CSP sandbox attribute on top-level page.
|
||||
|
||||
Minimal flags: allow-same-origin allow-scripts:
|
||||
Since we need to load the SimpleTest files, we have to set the
|
||||
allow-same-origin flag. Additionally, we set the allow-scripts flag
|
||||
since we need JS to check the flags.
|
||||
|
||||
Though not necessary, for this test we also set the allow-forms flag.
|
||||
We may later wish to extend the testing suite with sandbox_csp_top_*
|
||||
tests that set different permutations of the flags.
|
||||
|
||||
CSP header: Content-Security-Policy: sandbox allow-forms allow-scripts allow-same-origin
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Tests for Bug 671389</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<script type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// Check if two sandbox flags are the same.
|
||||
// getSandboxFlags returns a list of sandbox flags (if any) or
|
||||
// null if the flag is not set.
|
||||
// This function checks if two flags are the same, i.e., they're
|
||||
// either not set or have the same flags.
|
||||
function eqFlags(a, b) {
|
||||
if (a === null && b === null) { return true; }
|
||||
if (a === null || b === null) { return false; }
|
||||
if (a.length !== b.length) { return false; }
|
||||
var a_sorted = a.sort();
|
||||
var b_sorted = b.sort();
|
||||
for (var i in a_sorted) {
|
||||
if (a_sorted[i] !== b_sorted[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the sandbox flags of document doc.
|
||||
// If the flag is not set sandboxFlagsAsString returns null,
|
||||
// this function also returns null.
|
||||
// If the flag is set it may have some flags; in this case
|
||||
// this function returns the (potentially empty) list of flags.
|
||||
function getSandboxFlags(doc) {
|
||||
var flags = doc.sandboxFlagsAsString;
|
||||
if (flags === null) { return null; }
|
||||
return flags? flags.split(" "):[];
|
||||
}
|
||||
|
||||
function checkFlags(expected) {
|
||||
try {
|
||||
var flags = getSandboxFlags(SpecialPowers.wrap(document));
|
||||
ok(eqFlags(flags, expected), name + ' expected: "' + expected + '", got: "' + flags + '"');
|
||||
} catch (e) {
|
||||
ok(false, name + ' expected "' + expected + ', but failed with ' + e);
|
||||
}
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<body onLoad='checkFlags(["allow-forms", "allow-scripts", "allow-same-origin"]);'>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=671389">Mozilla Bug 671389</a> - Implement CSP sandbox directive
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
I am a top-level page sandboxed with "allow-scripts allow-forms
|
||||
allow-same-origin".
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1 @@
|
||||
Content-Security-Policy: sAnDbOx aLLow-FOrms aLlOw-ScRiPtS ALLOW-same-origin
|
@ -67,7 +67,7 @@ var tests = [
|
||||
},
|
||||
{
|
||||
policy1: "default-src 'unsafe-inline' 'sha256-uJXAPKP5NZxnVMZMUkDofh6a9P3UMRc1CRTevVPS/rI=' 'nonce-FooNonce' ",
|
||||
policy2: "sandbox allow-forms",
|
||||
policy2: "sandbox allow-scripts allow-same-origin",
|
||||
description: "unsafe-inline should *not* be ignored within default-src even if hash or nonce is specified",
|
||||
file: "file_ignore_unsafe_inline.html",
|
||||
result: "abcd",
|
||||
|
240
dom/security/test/csp/test_sandbox.html
Normal file
240
dom/security/test/csp/test_sandbox.html
Normal file
@ -0,0 +1,240 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Tests for bugs 886164 and 671389</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
</div>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var testCases = [
|
||||
{
|
||||
// Test 1: don't load image from non-same-origin; allow loading
|
||||
// images from same-same origin
|
||||
sandboxAttribute: "allow-same-origin",
|
||||
csp: "default-src 'self'",
|
||||
file: "file_sandbox_1.html",
|
||||
results: { img1a_good: -1, img1_bad: -1 }
|
||||
// fails if scripts execute
|
||||
},
|
||||
{
|
||||
// Test 2: don't load image from non-same-origin; allow loading
|
||||
// images from same-same origin, even without allow-same-origin
|
||||
// flag
|
||||
sandboxAttribute: "",
|
||||
csp: "default-src 'self'",
|
||||
file: "file_sandbox_2.html",
|
||||
results: { img2_bad: -1, img2a_good: -1 }
|
||||
// fails if scripts execute
|
||||
},
|
||||
{
|
||||
// Test 3: disallow loading images from any host, even with
|
||||
// allow-same-origin flag set
|
||||
sandboxAttribute: "allow-same-origin",
|
||||
csp: "default-src 'none'",
|
||||
file: "file_sandbox_3.html",
|
||||
results: { img3_bad: -1, img3a_bad: -1 },
|
||||
// fails if scripts execute
|
||||
},
|
||||
{
|
||||
// Test 4: disallow loading images from any host
|
||||
sandboxAttribute: "",
|
||||
csp: "default-src 'none'",
|
||||
file: "file_sandbox_4.html",
|
||||
results: { img4_bad: -1, img4a_bad: -1 }
|
||||
// fails if scripts execute
|
||||
},
|
||||
{
|
||||
// Test 5: disallow loading images or scripts, allow inline scripts
|
||||
sandboxAttribute: "allow-scripts",
|
||||
csp: "default-src 'none'; script-src 'unsafe-inline';",
|
||||
file: "file_sandbox_5.html",
|
||||
results: { img5_bad: -1, img5a_bad: -1, script5_bad: -1, script5a_bad: -1 },
|
||||
nrOKmessages: 2 // sends 2 ok message
|
||||
// fails if scripts execute
|
||||
},
|
||||
{
|
||||
// Test 6: disallow non-same-origin images, allow inline and same origin scripts
|
||||
sandboxAttribute: "allow-same-origin allow-scripts",
|
||||
csp: "default-src 'self' 'unsafe-inline';",
|
||||
file: "file_sandbox_6.html",
|
||||
results: { img6_bad: -1, script6_bad: -1 },
|
||||
nrOKmessages: 4 // sends 4 ok message
|
||||
// fails if forms are not disallowed
|
||||
},
|
||||
{
|
||||
// Test 7: same as Test 1
|
||||
csp: "default-src 'self'; sandbox allow-same-origin",
|
||||
file: "file_sandbox_7.html",
|
||||
results: { img7a_good: -1, img7_bad: -1 }
|
||||
},
|
||||
{
|
||||
// Test 8: same as Test 2
|
||||
csp: "sandbox allow-same-origin; default-src 'self'",
|
||||
file: "file_sandbox_8.html",
|
||||
results: { img8_bad: -1, img8a_good: -1 }
|
||||
},
|
||||
{
|
||||
// Test 9: same as Test 3
|
||||
csp: "default-src 'none'; sandbox allow-same-origin",
|
||||
file: "file_sandbox_9.html",
|
||||
results: { img9_bad: -1, img9a_bad: -1 }
|
||||
},
|
||||
{
|
||||
// Test 10: same as Test 4
|
||||
csp: "default-src 'none'; sandbox allow-same-origin",
|
||||
file: "file_sandbox_10.html",
|
||||
results: { img10_bad: -1, img10a_bad: -1 }
|
||||
},
|
||||
{
|
||||
// Test 11: same as Test 5
|
||||
csp: "default-src 'none'; script-src 'unsafe-inline'; sandbox allow-scripts allow-same-origin",
|
||||
file: "file_sandbox_11.html",
|
||||
results: { img11_bad: -1, img11a_bad: -1, script11_bad: -1, script11a_bad: -1 },
|
||||
nrOKmessages: 2 // sends 2 ok message
|
||||
},
|
||||
{
|
||||
// Test 12: same as Test 6
|
||||
csp: "sandbox allow-same-origin allow-scripts; default-src 'self' 'unsafe-inline';",
|
||||
file: "file_sandbox_12.html",
|
||||
results: { img12_bad: -1, script12_bad: -1 },
|
||||
nrOKmessages: 4 // sends 4 ok message
|
||||
},
|
||||
];
|
||||
|
||||
// a postMessage handler that is used by sandboxed iframes without
|
||||
// 'allow-same-origin' to communicate pass/fail back to this main page.
|
||||
// it expects to be called with an object like:
|
||||
// { ok: true/false,
|
||||
// desc: <description of the test> which it then forwards to ok() }
|
||||
window.addEventListener("message", receiveMessage, false);
|
||||
|
||||
function receiveMessage(event) {
|
||||
ok_wrapper(event.data.ok, event.data.desc);
|
||||
}
|
||||
|
||||
var completedTests = 0;
|
||||
var passedTests = 0;
|
||||
|
||||
var totalTests = (function() {
|
||||
var nrCSPloadTests = 0;
|
||||
for(var i = 0; i < testCases.length; i++) {
|
||||
nrCSPloadTests += Object.keys(testCases[i].results).length;
|
||||
if (testCases[i].nrOKmessages) {
|
||||
// + number of expected postMessages from iframe
|
||||
nrCSPloadTests += testCases[i].nrOKmessages;
|
||||
}
|
||||
}
|
||||
return nrCSPloadTests;
|
||||
})();
|
||||
|
||||
function ok_wrapper(result, desc) {
|
||||
ok(result, desc);
|
||||
|
||||
completedTests++;
|
||||
|
||||
if (result) {
|
||||
passedTests++;
|
||||
}
|
||||
|
||||
if (completedTests === totalTests) {
|
||||
window.examiner.remove();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
// Set the iframe src and sandbox attribute
|
||||
function runTest(test) {
|
||||
var iframe = document.createElement('iframe');
|
||||
|
||||
document.getElementById('content').appendChild(iframe);
|
||||
|
||||
// set sandbox attribute
|
||||
if (test.sandboxAttribute !== undefined) {
|
||||
iframe.sandbox = test.sandboxAttribute;
|
||||
}
|
||||
|
||||
// set query string
|
||||
var src = 'file_testserver.sjs';
|
||||
// path where the files are
|
||||
var path = '/tests/dom/security/test/csp/';
|
||||
|
||||
src += '?file=' + escape(path+test.file);
|
||||
|
||||
if (test.csp !== undefined) {
|
||||
src += '&csp=' + escape(test.csp);
|
||||
}
|
||||
|
||||
iframe.src = src;
|
||||
iframe.width = iframe.height = 10;
|
||||
}
|
||||
|
||||
// Examiner related
|
||||
|
||||
// This is used to watch the blocked data bounce off CSP and allowed data
|
||||
// get sent out to the wire.
|
||||
function examiner() {
|
||||
SpecialPowers.addObserver(this, "csp-on-violate-policy", false);
|
||||
SpecialPowers.addObserver(this, "specialpowers-http-notify-request", false);
|
||||
}
|
||||
|
||||
examiner.prototype = {
|
||||
observe: function(subject, topic, data) {
|
||||
var testpat = new RegExp("testid=([a-z0-9_]+)");
|
||||
|
||||
//_good things better be allowed!
|
||||
//_bad things better be stopped!
|
||||
|
||||
if (topic === "specialpowers-http-notify-request") {
|
||||
//these things were allowed by CSP
|
||||
var uri = data;
|
||||
if (!testpat.test(uri)) return;
|
||||
var testid = testpat.exec(uri)[1];
|
||||
|
||||
if(/_good/.test(testid)) {
|
||||
ok_wrapper(true, uri + " is allowed by csp");
|
||||
} else {
|
||||
ok_wrapper(false, uri + " should not be allowed by csp");
|
||||
}
|
||||
}
|
||||
|
||||
if(topic === "csp-on-violate-policy") {
|
||||
//these were blocked... record that they were blocked
|
||||
var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
|
||||
if (!testpat.test(asciiSpec)) return;
|
||||
var testid = testpat.exec(asciiSpec)[1];
|
||||
if(/_bad/.test(testid)) {
|
||||
ok_wrapper(true, asciiSpec + " was blocked by \"" + data + "\"");
|
||||
} else {
|
||||
ok_wrapper(false, asciiSpec + " should have been blocked by \"" + data + "\"");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// must eventually call this to remove the listener,
|
||||
// or mochitests might get borked.
|
||||
remove: function() {
|
||||
SpecialPowers.removeObserver(this, "csp-on-violate-policy");
|
||||
SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
|
||||
}
|
||||
}
|
||||
|
||||
window.examiner = new examiner();
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
(function() { // Run tests:
|
||||
for(var i = 0; i < testCases.length; i++) {
|
||||
runTest(testCases[i]);
|
||||
}
|
||||
})();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -93,7 +93,7 @@ function run_next_test() {
|
||||
return;
|
||||
}
|
||||
channel = setupChannel(curTest.contentType);
|
||||
channel.asyncOpen(new ChannelListener(), null);
|
||||
channel.asyncOpen2(new ChannelListener());
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
@ -20,7 +20,7 @@ dictionary CSP {
|
||||
sequence<DOMString> connect-src;
|
||||
sequence<DOMString> report-uri;
|
||||
sequence<DOMString> frame-ancestors;
|
||||
// sequence<DOMString> reflected-xss; // not suppored in Firefox
|
||||
// sequence<DOMString> reflected-xss; // not supported in Firefox
|
||||
sequence<DOMString> base-uri;
|
||||
sequence<DOMString> form-action;
|
||||
sequence<DOMString> referrer;
|
||||
@ -29,6 +29,7 @@ dictionary CSP {
|
||||
sequence<DOMString> child-src;
|
||||
sequence<DOMString> block-all-mixed-content;
|
||||
sequence<DOMString> require-sri-for;
|
||||
sequence<DOMString> sandbox;
|
||||
};
|
||||
|
||||
dictionary CSPPolicies {
|
||||
|
@ -392,6 +392,14 @@ partial interface Document {
|
||||
[ChromeOnly] readonly attribute boolean isSrcdocDocument;
|
||||
};
|
||||
|
||||
|
||||
// Extension to give chrome JS the ability to get the underlying
|
||||
// sandbox flag attribute
|
||||
partial interface Document {
|
||||
[ChromeOnly] readonly attribute DOMString? sandboxFlagsAsString;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Chrome document anonymous content management.
|
||||
* This is a Chrome-only API that allows inserting fixed positioned anonymous
|
||||
|
@ -13,8 +13,8 @@
|
||||
|
||||
dictionary EventListenerOptions {
|
||||
boolean capture = false;
|
||||
/* This is a Mozilla extension only available in Chrome and XBL.
|
||||
Setting to true make the listener be added to the system group. */
|
||||
/* Setting to true make the listener be added to the system group. */
|
||||
[Func="ThreadSafeIsChromeOrXBL"]
|
||||
boolean mozSystemGroup = false;
|
||||
};
|
||||
|
||||
|
@ -89,11 +89,11 @@ typedef any Transferable;
|
||||
Window implements GlobalEventHandlers;
|
||||
Window implements WindowEventHandlers;
|
||||
|
||||
[NoInterfaceObject, Exposed=(Window)]
|
||||
interface AppInstallEventHandlersMixin {
|
||||
// https://w3c.github.io/manifest/#oninstall-attribute
|
||||
partial interface Window {
|
||||
[Pref="dom.manifest.oninstall"]
|
||||
attribute EventHandler oninstall;
|
||||
};
|
||||
Window implements AppInstallEventHandlersMixin;
|
||||
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/
|
||||
[NoInterfaceObject, Exposed=(Window,Worker)]
|
||||
|
@ -228,7 +228,10 @@ SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0)
|
||||
GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get());
|
||||
SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode, Axis::BOTH);
|
||||
|
||||
if (stops->mCount >= 2) {
|
||||
if (stops->mCount < 2 ||
|
||||
!pat.mBegin.IsFinite() || !pat.mEnd.IsFinite()) {
|
||||
aPaint.setColor(SK_ColorTRANSPARENT);
|
||||
} else {
|
||||
SkPoint points[2];
|
||||
points[0] = SkPoint::Make(SkFloatToScalar(pat.mBegin.x), SkFloatToScalar(pat.mBegin.y));
|
||||
points[1] = SkPoint::Make(SkFloatToScalar(pat.mEnd.x), SkFloatToScalar(pat.mEnd.y));
|
||||
@ -241,8 +244,6 @@ SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0)
|
||||
stops->mCount,
|
||||
mode, 0, &mat);
|
||||
aPaint.setShader(shader);
|
||||
} else {
|
||||
aPaint.setColor(SK_ColorTRANSPARENT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -251,7 +252,11 @@ SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0)
|
||||
GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get());
|
||||
SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode, Axis::BOTH);
|
||||
|
||||
if (stops->mCount >= 2) {
|
||||
if (stops->mCount < 2 ||
|
||||
!pat.mCenter1.IsFinite() || !IsFinite(pat.mRadius1) ||
|
||||
!pat.mCenter2.IsFinite() || !IsFinite(pat.mRadius2)) {
|
||||
aPaint.setColor(SK_ColorTRANSPARENT);
|
||||
} else {
|
||||
SkPoint points[2];
|
||||
points[0] = SkPoint::Make(SkFloatToScalar(pat.mCenter1.x), SkFloatToScalar(pat.mCenter1.y));
|
||||
points[1] = SkPoint::Make(SkFloatToScalar(pat.mCenter2.x), SkFloatToScalar(pat.mCenter2.y));
|
||||
@ -267,8 +272,6 @@ SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0)
|
||||
stops->mCount,
|
||||
mode, 0, &mat);
|
||||
aPaint.setShader(shader);
|
||||
} else {
|
||||
aPaint.setColor(SK_ColorTRANSPARENT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -226,6 +226,18 @@ BufferTextureData::GetSize() const
|
||||
return ImageDataSerializer::SizeFromBufferDescriptor(mDescriptor);
|
||||
}
|
||||
|
||||
Maybe<gfx::IntSize>
|
||||
BufferTextureData::GetCbCrSize() const
|
||||
{
|
||||
return ImageDataSerializer::CbCrSizeFromBufferDescriptor(mDescriptor);
|
||||
}
|
||||
|
||||
Maybe<StereoMode>
|
||||
BufferTextureData::GetStereoMode() const
|
||||
{
|
||||
return ImageDataSerializer::StereoModeFromBufferDescriptor(mDescriptor);
|
||||
}
|
||||
|
||||
gfx::SurfaceFormat
|
||||
BufferTextureData::GetFormat() const
|
||||
{
|
||||
|
@ -52,9 +52,15 @@ public:
|
||||
// use TextureClient's default implementation
|
||||
virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) override;
|
||||
|
||||
virtual BufferTextureData* AsBufferTextureData() override { return this; }
|
||||
|
||||
// Don't use this.
|
||||
void SetDesciptor(const BufferDescriptor& aDesc);
|
||||
|
||||
Maybe<gfx::IntSize> GetCbCrSize() const;
|
||||
|
||||
Maybe<StereoMode> GetStereoMode() const;
|
||||
|
||||
protected:
|
||||
gfx::IntSize GetSize() const;
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "mozilla/layers/LayersMessages.h"
|
||||
#include "mozilla/layers/SharedPlanarYCbCrImage.h"
|
||||
#include "mozilla/layers/SharedRGBImage.h"
|
||||
#include "mozilla/layers/TextureClientRecycleAllocator.h"
|
||||
#include "nsISupportsUtils.h" // for NS_IF_ADDREF
|
||||
#include "YCbCrUtils.h" // for YCbCr conversions
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
@ -356,6 +357,10 @@ ImageContainer::ClearCachedResources()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
if (mImageClient && mImageClient->AsImageClientSingle()) {
|
||||
if (!mImageClient->HasTextureClientRecycler()) {
|
||||
return;
|
||||
}
|
||||
mImageClient->GetTextureClientRecycler()->ShrinkToMinimumSize();
|
||||
return;
|
||||
}
|
||||
return mRecycleBin->ClearRecycledBuffers();
|
||||
|
@ -128,6 +128,30 @@ gfx::IntSize SizeFromBufferDescriptor(const BufferDescriptor& aDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<gfx::IntSize> CbCrSizeFromBufferDescriptor(const BufferDescriptor& aDescriptor)
|
||||
{
|
||||
switch (aDescriptor.type()) {
|
||||
case BufferDescriptor::TRGBDescriptor:
|
||||
return Nothing();
|
||||
case BufferDescriptor::TYCbCrDescriptor:
|
||||
return Some(aDescriptor.get_YCbCrDescriptor().cbCrSize());
|
||||
default:
|
||||
MOZ_CRASH("GFX: CbCrSizeFromBufferDescriptor");
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<StereoMode> StereoModeFromBufferDescriptor(const BufferDescriptor& aDescriptor)
|
||||
{
|
||||
switch (aDescriptor.type()) {
|
||||
case BufferDescriptor::TRGBDescriptor:
|
||||
return Nothing();
|
||||
case BufferDescriptor::TYCbCrDescriptor:
|
||||
return Some(aDescriptor.get_YCbCrDescriptor().stereoMode());
|
||||
default:
|
||||
MOZ_CRASH("GFX: CbCrSizeFromBufferDescriptor");
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* GetYChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor)
|
||||
{
|
||||
return aBuffer + aDescriptor.yOffset();
|
||||
|
@ -58,6 +58,10 @@ gfx::SurfaceFormat FormatFromBufferDescriptor(const BufferDescriptor& aDescripto
|
||||
|
||||
gfx::IntSize SizeFromBufferDescriptor(const BufferDescriptor& aDescriptor);
|
||||
|
||||
Maybe<gfx::IntSize> CbCrSizeFromBufferDescriptor(const BufferDescriptor& aDescriptor);
|
||||
|
||||
Maybe<StereoMode> StereoModeFromBufferDescriptor(const BufferDescriptor& aDescriptor);
|
||||
|
||||
uint8_t* GetYChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor);
|
||||
|
||||
uint8_t* GetCbChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor);
|
||||
|
@ -692,8 +692,11 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
|
||||
|
||||
// When the mouse is outside the window we still want to handle dragging
|
||||
// but we won't find an APZC. Fallback to root APZC then.
|
||||
if (!apzc && mRootNode) {
|
||||
apzc = mRootNode->GetApzc();
|
||||
{ // scope lock
|
||||
MutexAutoLock lock(mTreeLock);
|
||||
if (!apzc && mRootNode) {
|
||||
apzc = mRootNode->GetApzc();
|
||||
}
|
||||
}
|
||||
|
||||
if (apzc) {
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "GeneratedJNIWrappers.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "OverscrollHandoffState.h"
|
||||
#include "OverScroller.h"
|
||||
#include "ViewConfiguration.h"
|
||||
|
||||
#define ANDROID_APZ_LOG(...)
|
||||
@ -33,9 +32,9 @@ AndroidSpecificState::AndroidSpecificState() {
|
||||
} else {
|
||||
ANDROID_APZ_LOG("%p Failed to get ViewConfiguration\n", this);
|
||||
}
|
||||
widget::sdk::OverScroller::LocalRef scroller;
|
||||
if (widget::sdk::OverScroller::New(widget::GeckoAppShell::GetApplicationContext(), &scroller) != NS_OK) {
|
||||
ANDROID_APZ_LOG("%p Failed to create Android OverScroller\n", this);
|
||||
widget::StackScroller::LocalRef scroller;
|
||||
if (widget::StackScroller::New(widget::GeckoAppShell::GetApplicationContext(), &scroller) != NS_OK) {
|
||||
ANDROID_APZ_LOG("%p Failed to create Android StackScroller\n", this);
|
||||
return;
|
||||
}
|
||||
mOverScroller = scroller;
|
||||
@ -75,6 +74,7 @@ AndroidFlingAnimation::AndroidFlingAnimation(AsyncPanZoomController& aApzc,
|
||||
, mScrolledApzc(aScrolledApzc)
|
||||
, mSentBounceX(false)
|
||||
, mSentBounceY(false)
|
||||
, mFlingDuration(0)
|
||||
{
|
||||
MOZ_ASSERT(mOverscrollHandoffChain);
|
||||
MOZ_ASSERT(aPlatformSpecificState->AsAndroidSpecificState());
|
||||
@ -120,7 +120,7 @@ AndroidFlingAnimation::AndroidFlingAnimation(AsyncPanZoomController& aApzc,
|
||||
(int32_t)(velocity.x * 1000.0f), (int32_t)(velocity.y * 1000.0f),
|
||||
(int32_t)floor(scrollRangeStartX), (int32_t)ceil(scrollRangeEndX),
|
||||
(int32_t)floor(scrollRangeStartY), (int32_t)ceil(scrollRangeEndY),
|
||||
0, 0);
|
||||
0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -135,10 +135,9 @@ AndroidFlingAnimation::DoSample(FrameMetrics& aFrameMetrics,
|
||||
{
|
||||
bool shouldContinueFling = true;
|
||||
|
||||
mOverScroller->ComputeScrollOffset(&shouldContinueFling);
|
||||
// OverScroller::GetCurrVelocity will sometimes return NaN. So need to externally
|
||||
// calculate current velocity and not rely on what the OverScroller calculates.
|
||||
// mOverScroller->GetCurrVelocity(&speed);
|
||||
mFlingDuration += aDelta.ToMilliseconds();
|
||||
mOverScroller->ComputeScrollOffset(mFlingDuration, &shouldContinueFling);
|
||||
|
||||
int32_t currentX = 0;
|
||||
int32_t currentY = 0;
|
||||
mOverScroller->GetCurrX(¤tX);
|
||||
@ -156,7 +155,12 @@ AndroidFlingAnimation::DoSample(FrameMetrics& aFrameMetrics,
|
||||
// of the fling, then end the animation.
|
||||
if (offset != mPreviousOffset) {
|
||||
if (aDelta.ToMilliseconds() > 0) {
|
||||
velocity = (offset - mPreviousOffset) / (float)aDelta.ToMilliseconds();
|
||||
mOverScroller->GetCurrSpeedX(&velocity.x);
|
||||
mOverScroller->GetCurrSpeedY(&velocity.y);
|
||||
|
||||
velocity.x /= 1000;
|
||||
velocity.y /= 1000;
|
||||
|
||||
mPreviousVelocity = velocity;
|
||||
}
|
||||
} else if (hitBoundX || hitBoundY) {
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "AsyncPanZoomAnimation.h"
|
||||
#include "AsyncPanZoomController.h"
|
||||
#include "GeneratedJNIWrappers.h"
|
||||
#include "OverScroller.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
@ -23,7 +22,7 @@ public:
|
||||
return this;
|
||||
}
|
||||
|
||||
widget::sdk::OverScroller::GlobalRef mOverScroller;
|
||||
widget::StackScroller::GlobalRef mOverScroller;
|
||||
};
|
||||
|
||||
class AndroidFlingAnimation: public AsyncPanZoomAnimation {
|
||||
@ -41,11 +40,12 @@ private:
|
||||
bool CheckBounds(Axis& aAxis, float aValue, float aDirection, float* aClamped);
|
||||
|
||||
AsyncPanZoomController& mApzc;
|
||||
widget::sdk::OverScroller::GlobalRef mOverScroller;
|
||||
widget::StackScroller::GlobalRef mOverScroller;
|
||||
RefPtr<const OverscrollHandoffChain> mOverscrollHandoffChain;
|
||||
RefPtr<const AsyncPanZoomController> mScrolledApzc;
|
||||
bool mSentBounceX;
|
||||
bool mSentBounceY;
|
||||
long mFlingDuration;
|
||||
ParentLayerPoint mStartOffset;
|
||||
ParentLayerPoint mPreviousOffset;
|
||||
// Unit vector in the direction of the fling.
|
||||
|
@ -16,6 +16,21 @@ function convertEntries(entries) {
|
||||
return result;
|
||||
}
|
||||
|
||||
function getPropertyAsRect(scrollFrames, scrollId, prop) {
|
||||
SimpleTest.ok(scrollId in scrollFrames,
|
||||
'expected scroll frame data for scroll id ' + scrollId);
|
||||
var scrollFrameData = scrollFrames[scrollId];
|
||||
SimpleTest.ok('displayport' in scrollFrameData,
|
||||
'expected a ' + prop + ' for scroll id ' + scrollId);
|
||||
var value = scrollFrameData[prop];
|
||||
var pieces = value.replace(/[()\s]+/g, '').split(',');
|
||||
SimpleTest.is(pieces.length, 4, "expected string of form (x,y,w,h)");
|
||||
return { x: parseInt(pieces[0]),
|
||||
y: parseInt(pieces[1]),
|
||||
w: parseInt(pieces[2]),
|
||||
h: parseInt(pieces[3]) };
|
||||
}
|
||||
|
||||
function convertScrollFrameData(scrollFrames) {
|
||||
var result = {};
|
||||
for (var i = 0; i < scrollFrames.length; ++i) {
|
||||
|
74
gfx/layers/apz/test/mochitest/helper_bug1280013.html
Normal file
74
gfx/layers/apz/test/mochitest/helper_bug1280013.html
Normal file
@ -0,0 +1,74 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html style="overflow:hidden">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- The viewport tag will result in APZ being in a "zoomed-in" state, assuming
|
||||
the device width is less than 980px. -->
|
||||
<meta name="viewport" content="width=980; initial-scale=1.0">
|
||||
<title>Test for bug 1280013</title>
|
||||
<script type="application/javascript" src="apz_test_native_event_utils.js"></script>
|
||||
<script type="application/javascript" src="apz_test_utils.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
|
||||
<script type="application/javascript">
|
||||
function* test(testDriver) {
|
||||
SimpleTest.ok(screen.height > 500, "Screen height must be at least 500 pixels for this test to work");
|
||||
|
||||
// This listener will trigger the test to continue once APZ is done with
|
||||
// processing the scroll.
|
||||
SpecialPowers.Services.obs.addObserver(testDriver, "APZ:TransformEnd", false);
|
||||
|
||||
// Scroll down to the iframe. Do it in two drags instead of one in case the
|
||||
// device screen is short
|
||||
yield synthesizeNativeTouchDrag(document.body, 10, 400, 0, -(350 + TOUCH_SLOP));
|
||||
yield synthesizeNativeTouchDrag(document.body, 10, 400, 0, -(350 + TOUCH_SLOP));
|
||||
// Now the top of the visible area should be at y=700 of the top-level page,
|
||||
// so if the screen is >= 500px tall, the entire iframe should be visible, at
|
||||
// least vertically.
|
||||
|
||||
// However, because of the overflow:hidden on the root elements, all this
|
||||
// scrolling is happening in APZ and is not reflected in the main-thread
|
||||
// scroll position (it is stored in the callback transform instead). We check
|
||||
// this by checking the scroll offset.
|
||||
yield flushApzRepaints(testDriver);
|
||||
SimpleTest.is(window.scrollY, 0, "Main-thread scroll position is still at 0");
|
||||
|
||||
// Scroll the iframe by 300px. Note that since the main-thread scroll position
|
||||
// is still 0, the subframe's getBoundingClientRect is going to be off by
|
||||
// 700 pixels, so we compensate for that here.
|
||||
var subframe = document.getElementById('subframe');
|
||||
yield synthesizeNativeTouchDrag(subframe, 10, 200 - 700, 0, -(300 + TOUCH_SLOP));
|
||||
|
||||
// Remove the observer, we don't need it any more.
|
||||
SpecialPowers.Services.obs.removeObserver(testDriver, "APZ:TransformEnd", false);
|
||||
|
||||
// Flush any pending paints
|
||||
yield flushApzRepaints(testDriver);
|
||||
|
||||
// get the displayport for the subframe
|
||||
var utils = SpecialPowers.getDOMWindowUtils(window);
|
||||
var contentPaints = utils.getContentAPZTestData().paints;
|
||||
var lastPaint = convertScrollFrameData(contentPaints[contentPaints.length - 1].scrollFrames);
|
||||
var foundIt = 0;
|
||||
for (var scrollId in lastPaint) {
|
||||
if (('contentDescription' in lastPaint[scrollId]) &&
|
||||
(lastPaint[scrollId]['contentDescription'].includes('tall_html'))) {
|
||||
var dp = getPropertyAsRect(lastPaint, scrollId, 'criticalDisplayport');
|
||||
SimpleTest.ok(dp.y <= 0, 'The critical displayport top should be less than or equal to zero to cover the visible part of the subframe; it is ' + dp.y);
|
||||
SimpleTest.ok(dp.y + dp.h >= subframe.clientHeight, 'The critical displayport bottom should be greater than the clientHeight; it is ' + (dp.y + dp.h));
|
||||
foundIt++;
|
||||
}
|
||||
}
|
||||
SimpleTest.is(foundIt, 1, "Found exactly one critical displayport for the subframe we were interested in.");
|
||||
}
|
||||
|
||||
waitUntilApzStable()
|
||||
.then(runContinuation(test))
|
||||
.then(subtestDone);
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body style="overflow:hidden">
|
||||
The iframe below is at (0, 800). Scroll it into view, and then scroll the contents. The content should be fully rendered in high-resolution.
|
||||
<iframe id="subframe" style="position:absolute; left: 0px; top: 800px; width: 600px; height: 350px" src="helper_tall.html"></iframe>
|
||||
</body>
|
||||
</html>
|
@ -72,23 +72,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=982141
|
||||
"expected a content paint with sequence number" + lastCompositorPaintSeqNo);
|
||||
var correspondingContentPaint = contentTestData.paints[lastCompositorPaintSeqNo];
|
||||
|
||||
// This content-side data should have a displayport for our scrollable <div>.
|
||||
SimpleTest.ok(childScrollId in correspondingContentPaint,
|
||||
"expected scroll frame data for scroll id " + childScrollId);
|
||||
SimpleTest.ok("displayport" in correspondingContentPaint[childScrollId],
|
||||
"expected a displayport for scroll id " + childScrollId);
|
||||
var childDisplayport = correspondingContentPaint[childScrollId]["displayport"];
|
||||
var dpFields = childDisplayport.replace(/[()\s]+/g, '').split(',');
|
||||
SimpleTest.is(dpFields.length, 4, "expected displayport string of form (x,y,w,h)");
|
||||
var dpWidth = dpFields[2];
|
||||
var dpHeight = dpFields[3];
|
||||
var dp = getPropertyAsRect(correspondingContentPaint, childScrollId, 'displayport');
|
||||
var subframe = document.getElementById('subframe');
|
||||
// The clientWidth and clientHeight may be less than 50 if there are scrollbars showing.
|
||||
// In general they will be (50 - <scrollbarwidth>, 50 - <scrollbarheight>).
|
||||
SimpleTest.ok(subframe.clientWidth > 0, "Expected a non-zero clientWidth, got: " + subframe.clientWidth);
|
||||
SimpleTest.ok(subframe.clientHeight > 0, "Expected a non-zero clientHeight, got: " + subframe.clientHeight);
|
||||
SimpleTest.ok(dpWidth >= subframe.clientWidth && dpHeight >= subframe.clientHeight,
|
||||
"expected a displayport at least as large as the scrollable element, got " + childDisplayport);
|
||||
SimpleTest.ok(dp.w >= subframe.clientWidth && dp.h >= subframe.clientHeight,
|
||||
"expected a displayport at least as large as the scrollable element, got " + JSON.stringify(dp));
|
||||
|
||||
window.opener.finishTest();
|
||||
}
|
||||
|
504
gfx/layers/apz/test/mochitest/helper_tall.html
Normal file
504
gfx/layers/apz/test/mochitest/helper_tall.html
Normal file
@ -0,0 +1,504 @@
|
||||
<html id="tall_html">
|
||||
<body>
|
||||
This is a tall page<br/>
|
||||
1<br/>
|
||||
2<br/>
|
||||
3<br/>
|
||||
4<br/>
|
||||
5<br/>
|
||||
6<br/>
|
||||
7<br/>
|
||||
8<br/>
|
||||
9<br/>
|
||||
10<br/>
|
||||
11<br/>
|
||||
12<br/>
|
||||
13<br/>
|
||||
14<br/>
|
||||
15<br/>
|
||||
16<br/>
|
||||
17<br/>
|
||||
18<br/>
|
||||
19<br/>
|
||||
20<br/>
|
||||
21<br/>
|
||||
22<br/>
|
||||
23<br/>
|
||||
24<br/>
|
||||
25<br/>
|
||||
26<br/>
|
||||
27<br/>
|
||||
28<br/>
|
||||
29<br/>
|
||||
30<br/>
|
||||
31<br/>
|
||||
32<br/>
|
||||
33<br/>
|
||||
34<br/>
|
||||
35<br/>
|
||||
36<br/>
|
||||
37<br/>
|
||||
38<br/>
|
||||
39<br/>
|
||||
40<br/>
|
||||
41<br/>
|
||||
42<br/>
|
||||
43<br/>
|
||||
44<br/>
|
||||
45<br/>
|
||||
46<br/>
|
||||
47<br/>
|
||||
48<br/>
|
||||
49<br/>
|
||||
50<br/>
|
||||
51<br/>
|
||||
52<br/>
|
||||
53<br/>
|
||||
54<br/>
|
||||
55<br/>
|
||||
56<br/>
|
||||
57<br/>
|
||||
58<br/>
|
||||
59<br/>
|
||||
60<br/>
|
||||
61<br/>
|
||||
62<br/>
|
||||
63<br/>
|
||||
64<br/>
|
||||
65<br/>
|
||||
66<br/>
|
||||
67<br/>
|
||||
68<br/>
|
||||
69<br/>
|
||||
70<br/>
|
||||
71<br/>
|
||||
72<br/>
|
||||
73<br/>
|
||||
74<br/>
|
||||
75<br/>
|
||||
76<br/>
|
||||
77<br/>
|
||||
78<br/>
|
||||
79<br/>
|
||||
80<br/>
|
||||
81<br/>
|
||||
82<br/>
|
||||
83<br/>
|
||||
84<br/>
|
||||
85<br/>
|
||||
86<br/>
|
||||
87<br/>
|
||||
88<br/>
|
||||
89<br/>
|
||||
90<br/>
|
||||
91<br/>
|
||||
92<br/>
|
||||
93<br/>
|
||||
94<br/>
|
||||
95<br/>
|
||||
96<br/>
|
||||
97<br/>
|
||||
98<br/>
|
||||
99<br/>
|
||||
100<br/>
|
||||
101<br/>
|
||||
102<br/>
|
||||
103<br/>
|
||||
104<br/>
|
||||
105<br/>
|
||||
106<br/>
|
||||
107<br/>
|
||||
108<br/>
|
||||
109<br/>
|
||||
110<br/>
|
||||
111<br/>
|
||||
112<br/>
|
||||
113<br/>
|
||||
114<br/>
|
||||
115<br/>
|
||||
116<br/>
|
||||
117<br/>
|
||||
118<br/>
|
||||
119<br/>
|
||||
120<br/>
|
||||
121<br/>
|
||||
122<br/>
|
||||
123<br/>
|
||||
124<br/>
|
||||
125<br/>
|
||||
126<br/>
|
||||
127<br/>
|
||||
128<br/>
|
||||
129<br/>
|
||||
130<br/>
|
||||
131<br/>
|
||||
132<br/>
|
||||
133<br/>
|
||||
134<br/>
|
||||
135<br/>
|
||||
136<br/>
|
||||
137<br/>
|
||||
138<br/>
|
||||
139<br/>
|
||||
140<br/>
|
||||
141<br/>
|
||||
142<br/>
|
||||
143<br/>
|
||||
144<br/>
|
||||
145<br/>
|
||||
146<br/>
|
||||
147<br/>
|
||||
148<br/>
|
||||
149<br/>
|
||||
150<br/>
|
||||
151<br/>
|
||||
152<br/>
|
||||
153<br/>
|
||||
154<br/>
|
||||
155<br/>
|
||||
156<br/>
|
||||
157<br/>
|
||||
158<br/>
|
||||
159<br/>
|
||||
160<br/>
|
||||
161<br/>
|
||||
162<br/>
|
||||
163<br/>
|
||||
164<br/>
|
||||
165<br/>
|
||||
166<br/>
|
||||
167<br/>
|
||||
168<br/>
|
||||
169<br/>
|
||||
170<br/>
|
||||
171<br/>
|
||||
172<br/>
|
||||
173<br/>
|
||||
174<br/>
|
||||
175<br/>
|
||||
176<br/>
|
||||
177<br/>
|
||||
178<br/>
|
||||
179<br/>
|
||||
180<br/>
|
||||
181<br/>
|
||||
182<br/>
|
||||
183<br/>
|
||||
184<br/>
|
||||
185<br/>
|
||||
186<br/>
|
||||
187<br/>
|
||||
188<br/>
|
||||
189<br/>
|
||||
190<br/>
|
||||
191<br/>
|
||||
192<br/>
|
||||
193<br/>
|
||||
194<br/>
|
||||
195<br/>
|
||||
196<br/>
|
||||
197<br/>
|
||||
198<br/>
|
||||
199<br/>
|
||||
200<br/>
|
||||
201<br/>
|
||||
202<br/>
|
||||
203<br/>
|
||||
204<br/>
|
||||
205<br/>
|
||||
206<br/>
|
||||
207<br/>
|
||||
208<br/>
|
||||
209<br/>
|
||||
210<br/>
|
||||
211<br/>
|
||||
212<br/>
|
||||
213<br/>
|
||||
214<br/>
|
||||
215<br/>
|
||||
216<br/>
|
||||
217<br/>
|
||||
218<br/>
|
||||
219<br/>
|
||||
220<br/>
|
||||
221<br/>
|
||||
222<br/>
|
||||
223<br/>
|
||||
224<br/>
|
||||
225<br/>
|
||||
226<br/>
|
||||
227<br/>
|
||||
228<br/>
|
||||
229<br/>
|
||||
230<br/>
|
||||
231<br/>
|
||||
232<br/>
|
||||
233<br/>
|
||||
234<br/>
|
||||
235<br/>
|
||||
236<br/>
|
||||
237<br/>
|
||||
238<br/>
|
||||
239<br/>
|
||||
240<br/>
|
||||
241<br/>
|
||||
242<br/>
|
||||
243<br/>
|
||||
244<br/>
|
||||
245<br/>
|
||||
246<br/>
|
||||
247<br/>
|
||||
248<br/>
|
||||
249<br/>
|
||||
250<br/>
|
||||
251<br/>
|
||||
252<br/>
|
||||
253<br/>
|
||||
254<br/>
|
||||
255<br/>
|
||||
256<br/>
|
||||
257<br/>
|
||||
258<br/>
|
||||
259<br/>
|
||||
260<br/>
|
||||
261<br/>
|
||||
262<br/>
|
||||
263<br/>
|
||||
264<br/>
|
||||
265<br/>
|
||||
266<br/>
|
||||
267<br/>
|
||||
268<br/>
|
||||
269<br/>
|
||||
270<br/>
|
||||
271<br/>
|
||||
272<br/>
|
||||
273<br/>
|
||||
274<br/>
|
||||
275<br/>
|
||||
276<br/>
|
||||
277<br/>
|
||||
278<br/>
|
||||
279<br/>
|
||||
280<br/>
|
||||
281<br/>
|
||||
282<br/>
|
||||
283<br/>
|
||||
284<br/>
|
||||
285<br/>
|
||||
286<br/>
|
||||
287<br/>
|
||||
288<br/>
|
||||
289<br/>
|
||||
290<br/>
|
||||
291<br/>
|
||||
292<br/>
|
||||
293<br/>
|
||||
294<br/>
|
||||
295<br/>
|
||||
296<br/>
|
||||
297<br/>
|
||||
298<br/>
|
||||
299<br/>
|
||||
300<br/>
|
||||
301<br/>
|
||||
302<br/>
|
||||
303<br/>
|
||||
304<br/>
|
||||
305<br/>
|
||||
306<br/>
|
||||
307<br/>
|
||||
308<br/>
|
||||
309<br/>
|
||||
310<br/>
|
||||
311<br/>
|
||||
312<br/>
|
||||
313<br/>
|
||||
314<br/>
|
||||
315<br/>
|
||||
316<br/>
|
||||
317<br/>
|
||||
318<br/>
|
||||
319<br/>
|
||||
320<br/>
|
||||
321<br/>
|
||||
322<br/>
|
||||
323<br/>
|
||||
324<br/>
|
||||
325<br/>
|
||||
326<br/>
|
||||
327<br/>
|
||||
328<br/>
|
||||
329<br/>
|
||||
330<br/>
|
||||
331<br/>
|
||||
332<br/>
|
||||
333<br/>
|
||||
334<br/>
|
||||
335<br/>
|
||||
336<br/>
|
||||
337<br/>
|
||||
338<br/>
|
||||
339<br/>
|
||||
340<br/>
|
||||
341<br/>
|
||||
342<br/>
|
||||
343<br/>
|
||||
344<br/>
|
||||
345<br/>
|
||||
346<br/>
|
||||
347<br/>
|
||||
348<br/>
|
||||
349<br/>
|
||||
350<br/>
|
||||
351<br/>
|
||||
352<br/>
|
||||
353<br/>
|
||||
354<br/>
|
||||
355<br/>
|
||||
356<br/>
|
||||
357<br/>
|
||||
358<br/>
|
||||
359<br/>
|
||||
360<br/>
|
||||
361<br/>
|
||||
362<br/>
|
||||
363<br/>
|
||||
364<br/>
|
||||
365<br/>
|
||||
366<br/>
|
||||
367<br/>
|
||||
368<br/>
|
||||
369<br/>
|
||||
370<br/>
|
||||
371<br/>
|
||||
372<br/>
|
||||
373<br/>
|
||||
374<br/>
|
||||
375<br/>
|
||||
376<br/>
|
||||
377<br/>
|
||||
378<br/>
|
||||
379<br/>
|
||||
380<br/>
|
||||
381<br/>
|
||||
382<br/>
|
||||
383<br/>
|
||||
384<br/>
|
||||
385<br/>
|
||||
386<br/>
|
||||
387<br/>
|
||||
388<br/>
|
||||
389<br/>
|
||||
390<br/>
|
||||
391<br/>
|
||||
392<br/>
|
||||
393<br/>
|
||||
394<br/>
|
||||
395<br/>
|
||||
396<br/>
|
||||
397<br/>
|
||||
398<br/>
|
||||
399<br/>
|
||||
400<br/>
|
||||
401<br/>
|
||||
402<br/>
|
||||
403<br/>
|
||||
404<br/>
|
||||
405<br/>
|
||||
406<br/>
|
||||
407<br/>
|
||||
408<br/>
|
||||
409<br/>
|
||||
410<br/>
|
||||
411<br/>
|
||||
412<br/>
|
||||
413<br/>
|
||||
414<br/>
|
||||
415<br/>
|
||||
416<br/>
|
||||
417<br/>
|
||||
418<br/>
|
||||
419<br/>
|
||||
420<br/>
|
||||
421<br/>
|
||||
422<br/>
|
||||
423<br/>
|
||||
424<br/>
|
||||
425<br/>
|
||||
426<br/>
|
||||
427<br/>
|
||||
428<br/>
|
||||
429<br/>
|
||||
430<br/>
|
||||
431<br/>
|
||||
432<br/>
|
||||
433<br/>
|
||||
434<br/>
|
||||
435<br/>
|
||||
436<br/>
|
||||
437<br/>
|
||||
438<br/>
|
||||
439<br/>
|
||||
440<br/>
|
||||
441<br/>
|
||||
442<br/>
|
||||
443<br/>
|
||||
444<br/>
|
||||
445<br/>
|
||||
446<br/>
|
||||
447<br/>
|
||||
448<br/>
|
||||
449<br/>
|
||||
450<br/>
|
||||
451<br/>
|
||||
452<br/>
|
||||
453<br/>
|
||||
454<br/>
|
||||
455<br/>
|
||||
456<br/>
|
||||
457<br/>
|
||||
458<br/>
|
||||
459<br/>
|
||||
460<br/>
|
||||
461<br/>
|
||||
462<br/>
|
||||
463<br/>
|
||||
464<br/>
|
||||
465<br/>
|
||||
466<br/>
|
||||
467<br/>
|
||||
468<br/>
|
||||
469<br/>
|
||||
470<br/>
|
||||
471<br/>
|
||||
472<br/>
|
||||
473<br/>
|
||||
474<br/>
|
||||
475<br/>
|
||||
476<br/>
|
||||
477<br/>
|
||||
478<br/>
|
||||
479<br/>
|
||||
480<br/>
|
||||
481<br/>
|
||||
482<br/>
|
||||
483<br/>
|
||||
484<br/>
|
||||
485<br/>
|
||||
486<br/>
|
||||
487<br/>
|
||||
488<br/>
|
||||
489<br/>
|
||||
490<br/>
|
||||
491<br/>
|
||||
492<br/>
|
||||
493<br/>
|
||||
494<br/>
|
||||
495<br/>
|
||||
496<br/>
|
||||
497<br/>
|
||||
498<br/>
|
||||
499<br/>
|
||||
</body>
|
||||
</html>
|
@ -22,6 +22,8 @@ support-files =
|
||||
helper_touch_action_regions.html
|
||||
helper_scroll_inactive_perspective.html
|
||||
helper_scroll_inactive_zindex.html
|
||||
helper_bug1280013.html
|
||||
helper_tall.html
|
||||
helper_drag_scroll.html
|
||||
tags = apz
|
||||
[test_bug982141.html]
|
||||
@ -54,3 +56,5 @@ skip-if = (toolkit == 'android') # wheel events not supported on mobile
|
||||
skip-if = (toolkit == 'android') || (toolkit == 'cocoa') # wheel events not supported on mobile, and synthesized wheel smooth-scrolling not supported on OS X
|
||||
[test_bug1253683.html]
|
||||
skip-if = (os == 'android') || (os == 'b2g') # uses wheel events which are not supported on mobile
|
||||
[test_group_zoom.html]
|
||||
skip-if = (toolkit != 'android') # only android supports zoom
|
||||
|
44
gfx/layers/apz/test/mochitest/test_group_zoom.html
Normal file
44
gfx/layers/apz/test/mochitest/test_group_zoom.html
Normal file
@ -0,0 +1,44 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Various zoom-related tests that spawn in new windows</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="apz_test_utils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
var prefs = [
|
||||
// We need the APZ paint logging information
|
||||
["apz.test.logging_enabled", true],
|
||||
// Dropping the touch slop to 0 makes the tests easier to write because
|
||||
// we can just do a one-pixel drag to get over the pan threshold rather
|
||||
// than having to hard-code some larger value.
|
||||
["apz.touch_start_tolerance", "0.0"],
|
||||
// The subtests in this test do touch-drags to pan the page, but we don't
|
||||
// want those pans to turn into fling animations, so we increase the
|
||||
// fling-stop threshold velocity to absurdly high.
|
||||
["apz.fling_stopped_threshold", "10000"],
|
||||
// The helper_bug1280013's div gets a displayport on scroll, but if the
|
||||
// test takes too long the displayport can expire before we read the value
|
||||
// out of the test. So we disable displayport expiry for these tests.
|
||||
["apz.displayport_expiry_ms", 0],
|
||||
];
|
||||
|
||||
var subtests = [
|
||||
{'file': 'helper_bug1280013.html', 'prefs': prefs},
|
||||
];
|
||||
|
||||
if (isApzEnabled()) {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
window.onload = function() {
|
||||
runSubtestsSeriallyInFreshWindows(subtests)
|
||||
.then(SimpleTest.finish);
|
||||
};
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
@ -408,8 +408,8 @@ APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput,
|
||||
// that's not on the Root Document (RD). That is, on platforms where
|
||||
// RCD == RD, it's 1, and on platforms where RCD != RD, it's the RCD
|
||||
// resolution. 'input' has this resolution applied, but the scroll
|
||||
// deltas retrieved below do not, so we need to apply them to the
|
||||
// deltas before adding the deltas to 'input'. (Technically, deltas
|
||||
// delta retrieved below do not, so we need to apply them to the
|
||||
// delta before adding the delta to 'input'. (Technically, deltas
|
||||
// from scroll frames outside the RCD would already have this
|
||||
// resolution applied, but we don't have such scroll frames in
|
||||
// practice.)
|
||||
@ -417,30 +417,10 @@ APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput,
|
||||
if (nsIPresShell* shell = GetRootContentDocumentPresShellForContent(content)) {
|
||||
nonRootResolution = shell->GetCumulativeNonRootScaleResolution();
|
||||
}
|
||||
// Now apply the callback-transform.
|
||||
// XXX: Walk up the frame tree from the frame of this content element
|
||||
// to the root of the frame tree, and apply any apzCallbackTransform
|
||||
// found on the way. This is only approximately correct, as it does
|
||||
// not take into account CSS transforms, nor differences in structure between
|
||||
// the frame tree (which determines the transforms we're applying)
|
||||
// and the layer tree (which determines the transforms we *want* to
|
||||
// apply).
|
||||
nsIFrame* frame = content->GetPrimaryFrame();
|
||||
nsCOMPtr<nsIContent> lastContent;
|
||||
while (frame) {
|
||||
if (content && (content != lastContent)) {
|
||||
void* property = content->GetProperty(nsGkAtoms::apzCallbackTransform);
|
||||
if (property) {
|
||||
CSSPoint delta = (*static_cast<CSSPoint*>(property));
|
||||
delta = delta * nonRootResolution;
|
||||
input += delta;
|
||||
}
|
||||
}
|
||||
frame = frame->GetParent();
|
||||
lastContent = content;
|
||||
content = frame ? frame->GetContent() : nullptr;
|
||||
}
|
||||
return input;
|
||||
// Now apply the callback-transform. This is only approximately correct,
|
||||
// see the comment on GetCumulativeApzCallbackTransform for details.
|
||||
CSSPoint transform = nsLayoutUtils::GetCumulativeApzCallbackTransform(content->GetPrimaryFrame());
|
||||
return input + transform * nonRootResolution;
|
||||
}
|
||||
|
||||
LayoutDeviceIntPoint
|
||||
|
@ -425,9 +425,16 @@ ClientTiledPaintedLayer::RenderLayer()
|
||||
IntSize layerSize = mVisibleRegion.ToUnknownRegion().GetBounds().Size();
|
||||
IntSize tileSize(gfxPlatform::GetPlatform()->GetTileWidth(),
|
||||
gfxPlatform::GetPlatform()->GetTileHeight());
|
||||
bool isHalfTileWidthOrHeight = layerSize.width <= tileSize.width / 2 ||
|
||||
layerSize.height <= tileSize.height / 2;
|
||||
|
||||
// Use single tile when layer is not scrollable, is smaller than one
|
||||
// tile, or when more than half of the tiles' pixels in either
|
||||
// dimension would be wasted.
|
||||
bool wantSingleTiledContentClient =
|
||||
(mCreationHint == LayerManager::NONE || layerSize <= tileSize) &&
|
||||
(mCreationHint == LayerManager::NONE ||
|
||||
layerSize <= tileSize ||
|
||||
isHalfTileWidthOrHeight) &&
|
||||
SingleTiledContentClient::ClientSupportsLayerSize(layerSize, ClientManager()) &&
|
||||
gfxPrefs::LayersSingleTileEnabled();
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user