merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2016-06-30 12:33:41 +02:00
commit 3a42c363cc
273 changed files with 7594 additions and 2600 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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();

View File

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

View File

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

View File

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

View File

@ -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()
{

View File

@ -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.
*/

View File

@ -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()) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

@ -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="&#x09;allow-same-origin&#x09;allow-scripts&#x09;" 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>

View File

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

View File

@ -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();

View File

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

View File

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

View File

@ -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 = Couldnt parse invalid sandbox flag %1$S

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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()
{

View File

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

View File

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

View File

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

View File

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

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

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

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

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

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

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

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

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

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

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

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

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

View 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=...>");

View 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=...>");

View File

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

View 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]

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

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

View File

@ -0,0 +1 @@
Content-Security-Policy: sAnDbOx aLLow-FOrms aLlOw-ScRiPtS ALLOW-same-origin

View File

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

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

View File

@ -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() {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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();

View File

@ -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();

View File

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

View File

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

View File

@ -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(&currentX);
@ -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) {

View File

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

View File

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

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

View File

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

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

View File

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

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

View File

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

View File

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