Merge mozilla-central to autoland

This commit is contained in:
Carsten "Tomcat" Book 2017-04-19 10:57:24 +02:00
commit 7bcdfe36bc
79 changed files with 4423 additions and 337 deletions

View File

@ -6248,7 +6248,7 @@
if (width != this.mTabstripWidth) {
this.adjustTabstrip();
this._fillTrailingGap();
this._handleTabSelect();
this._handleTabSelect(false);
this.mTabstripWidth = width;
}
break;

View File

@ -11,4 +11,4 @@ BROWSER_CHROME_MANIFESTS += [
JAR_MANIFESTS += ['jar.mn']
with Files('**'):
BUG_COMPONENT = ('Firefox', 'Contextual Identity')
BUG_COMPONENT = ('DOM', 'Security')

View File

@ -67,6 +67,7 @@ support-files =
[browser_ext_incognito_popup.js]
[browser_ext_lastError.js]
[browser_ext_omnibox.js]
skip-if = debug || asan # Bug 1354681
[browser_ext_optionsPage_browser_style.js]
[browser_ext_optionsPage_privileges.js]
[browser_ext_pageAction_context.js]

View File

@ -1225,7 +1225,7 @@
</xul:menupopup>
</content>
<implementation implements="nsIDOMEventListener">
<implementation implements="nsIDOMEventListener,nsIObserver,nsIWeakReference">
<!-- Width in pixels of the one-off buttons. 49px is the min-width of
each search engine button, adapt this const when changing the css.
@ -1273,6 +1273,7 @@
</property>
<field name="_textbox">null</field>
<field name="_textboxWidth">0</field>
<!-- The textbox associated with the one-offs. Set this to a textbox to
automatically keep the related one-offs UI up to date. Otherwise you
@ -1415,6 +1416,10 @@
this._ignoreMouseEvents = false;
aEvent.stopPropagation();
});
// Add weak referenced observers to invalidate our cached list of engines.
Services.prefs.addObserver("browser.search.hiddenOneOffs", this, true);
Services.obs.addObserver(this, "browser-search-engine-modified", true);
]]></constructor>
<!-- This handles events outside the one-off buttons, like on the popup
@ -1443,6 +1448,16 @@
]]></body>
</method>
<method name="observe">
<parameter name="aEngine"/>
<parameter name="aTopic"/>
<parameter name="aData"/>
<body><![CDATA[
// Make sure the engine list is refetched next time it's needed.
this._engines = null;
]]></body>
</method>
<method name="showSettings">
<body><![CDATA[
BrowserUITelemetry.countSearchSettingsEvent(this.telemetryOrigin);
@ -1491,20 +1506,60 @@
]]></body>
</method>
<field name="_engines">null</field>
<property name="engines" readonly="true">
<getter><![CDATA[
if (this._engines)
return this._engines;
let currentEngineNameToIgnore;
if (!this.getAttribute("includecurrentengine"))
currentEngineNameToIgnore = Services.search.currentEngine.name;
let pref = Services.prefs.getStringPref("browser.search.hiddenOneOffs");
let hiddenList = pref ? pref.split(",") : [];
this._engines = Services.search.getVisibleEngines().filter(e => {
let name = e.name;
return (!currentEngineNameToIgnore ||
name != currentEngineNameToIgnore) &&
!hiddenList.includes(name);
});
return this._engines;
]]></getter>
</property>
<!-- Builds all the UI. -->
<method name="_rebuild">
<body><![CDATA[
// Update the 'Search for <keywords> with:" header.
this._updateAfterQueryChanged();
let list = document.getAnonymousElementByAttribute(this, "anonid",
"search-panel-one-offs");
// Handle opensearch items. This needs to be done before building the
// list of one off providers, as that code will return early if all the
// alternative engines are hidden.
this._rebuildAddEngineList();
// Skip this in compact mode, ie. for the urlbar.
if (!this.compact)
this._rebuildAddEngineList();
// Check if the one-off buttons really need to be rebuilt.
if (this._textbox) {
// We can't get a reliable value for the popup width without flushing,
// but the popup width won't change if the textbox width doesn't.
let DOMUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let textboxWidth =
DOMUtils.getBoundsWithoutFlushing(this._textbox).width;
// We can return early if neither the list of engines nor the panel
// width has changed.
if (this._engines && this._textboxWidth == textboxWidth) {
return;
}
this._textboxWidth = textboxWidth;
}
let list = document.getAnonymousElementByAttribute(this, "anonid",
"search-panel-one-offs");
let settingsButton =
document.getAnonymousElementByAttribute(this, "anonid",
"search-settings-compact");
@ -1516,24 +1571,15 @@
if (settingsButton.nextSibling)
settingsButton.nextSibling.remove();
let Preferences =
Cu.import("resource://gre/modules/Preferences.jsm", {}).Preferences;
let pref = Preferences.get("browser.search.hiddenOneOffs");
let hiddenList = pref ? pref.split(",") : [];
let currentEngineName = Services.search.currentEngine.name;
let includeCurrentEngine = this.getAttribute("includecurrentengine");
let engines = Services.search.getVisibleEngines().filter(e => {
return (includeCurrentEngine || e.name != currentEngineName) &&
!hiddenList.includes(e.name);
});
let engines = this.engines;
let oneOffCount = engines.length;
let header = document.getAnonymousElementByAttribute(this, "anonid",
"search-panel-one-offs-header")
// header is a xul:deck so collapsed doesn't work on it, see bug 589569.
header.hidden = list.collapsed = !engines.length;
header.hidden = list.collapsed = !oneOffCount;
if (!engines.length)
if (!oneOffCount)
return;
let panelWidth = parseInt(this.popup.clientWidth);
@ -1547,7 +1593,6 @@
// If the <description> tag with the list of search engines doesn't have
// a fixed height, the panel will be sized incorrectly, causing the bottom
// of the suggestion <tree> to be hidden.
let oneOffCount = engines.length;
if (this.compact)
++oneOffCount;
let rowCount = Math.ceil(oneOffCount / enginesPerRow);
@ -1647,20 +1692,12 @@
}
// Add a button for each engine that the page in the selected browser
// offers, but with the following exceptions:
//
// (1) Not when the one-offs are compact. Compact one-offs are shown in
// the urlbar, and the add-engine buttons span the width of the popup,
// so if we added all the engines that a page offers, it could break the
// urlbar popup by offering a ton of engines. We should probably make a
// smaller version of the buttons for compact one-offs.
//
// (2) Not when there are too many offered engines. The popup isn't
// designed to handle too many (by scrolling for example), so a page
// could break the popup by offering too many. Instead, add a single
// menu button with a submenu of all the engines.
// offers, except when there are too many offered engines.
// The popup isn't designed to handle too many (by scrolling for
// example), so a page could break the popup by offering too many.
// Instead, add a single menu button with a submenu of all the engines.
if (this.compact || !gBrowser.selectedBrowser.engines) {
if (!gBrowser.selectedBrowser.engines) {
return;
}

View File

@ -96,6 +96,6 @@ skip-if = os == "mac" && os_version == "10.8" || os == "win" && os_version == "5
[browser_two_tabs.js]
# We want these tests to run for mochitest-dt as well, so we include them here:
[../../../../browser/base/content/test/static/browser_parsable_css.js]
skip-if = debug # no point in running on both opt and debug, and will likely intermittently timeout on debug
skip-if = debug || asan # no point in running on both opt and debug, and will likely intermittently timeout on debug
[../../../../browser/base/content/test/static/browser_all_files_referenced.js]
skip-if = debug # no point in running on both opt and debug, and will likely intermittently timeout on debug
skip-if = debug || asan # no point in running on both opt and debug, and will likely intermittently timeout on debug

View File

@ -60,20 +60,14 @@ module.exports = createClass({
className: "boxmodel-properties-header",
onDoubleClick: this.onToggleExpander,
},
dom.div(
dom.span(
{
className: "boxmodel-properties-expander theme-twisty",
open: this.state.isOpen,
onClick: this.onToggleExpander,
}
),
dom.span(
{
className: "boxmodel-properties-label",
title: BOXMODEL_L10N.getStr("boxmodel.propertiesLabel"),
},
BOXMODEL_L10N.getStr("boxmodel.propertiesLabel")
)
BOXMODEL_L10N.getStr("boxmodel.propertiesLabel")
),
dom.div(
{

View File

@ -56,7 +56,9 @@ module.exports = createClass({
dom.ul(
{},
dom.li(
{},
{
className: "grid-settings-item",
},
dom.label(
{},
dom.input(
@ -70,7 +72,9 @@ module.exports = createClass({
)
),
dom.li(
{},
{
className: "grid-settings-item",
},
dom.label(
{},
dom.input(

View File

@ -118,9 +118,7 @@ module.exports = createClass({
let { nodeFront } = grid;
return dom.li(
{
className: "grid-item",
},
{},
dom.label(
{},
dom.input(

View File

@ -52,6 +52,7 @@ const App = createClass({
return dom.div(
{
id: "layout-container",
className: "devtools-monospace",
},
Accordion({
items: [

View File

@ -8,6 +8,7 @@
.boxmodel-container {
overflow: auto;
padding-bottom: 4px;
}
/* Header */
@ -112,7 +113,8 @@
.boxmodel-main > p > span,
.boxmodel-main > p > input,
.boxmodel-content {
.boxmodel-content,
.boxmodel-size > span {
vertical-align: middle;
pointer-events: auto;
}
@ -314,12 +316,16 @@
/* Box Model Properties: contains a list of relevant box model properties */
.boxmodel-properties-header {
display: flex;
padding: 2px 0;
padding: 2px 3px;
}
.boxmodel-properties-wrapper {
padding: 0 9px;
.boxmodel-properties-expander {
vertical-align: middle;
display: inline-block;
}
.boxmodel-properties-wrapper .property-view {
padding-inline-start: 17px;
}
.boxmodel-properties-wrapper .property-name-container {

View File

@ -16,13 +16,15 @@
.grid-container {
display: flex;
flex-direction: column;
flex: 1;
flex: 1 auto;
align-items: center;
min-width: 140px;
}
.grid-container > span {
font-weight: bold;
margin-bottom: 3px;
font-weight: 600;
margin-bottom: 5px;
pointer-events: none;
}
.grid-container > ul {
@ -32,9 +34,20 @@
}
.grid-container li {
display: flex;
align-items: center;
padding: 4px 0;
}
.grid-container input {
margin: 0 5px;
}
.grid-container label {
display: flex;
align-items: center;
}
/**
* Grid Container
*/
@ -45,13 +58,28 @@
margin: 5px;
}
/**
* Grid Outline
*/
.grid-outline {
margin-top: 10px;
overflow: visible;
}
/**
* Grid Content
*/
.grid-content {
display: flex;
flex-wrap: wrap;
flex: 1;
margin-top: 10px;
}
.grid-container:first-child {
margin-bottom: 10px;
}
/**
@ -97,15 +125,6 @@
* Grid Item
*/
.grid-item {
display: flex;
align-items: center;
}
.grid-item input {
margin: 0 5px;
}
.grid-color-swatch {
width: 12px;
height: 12px;
@ -118,3 +137,11 @@
.grid-color-value {
display: none;
}
/**
* Settings Item
*/
.grid-settings-item label {
line-height: 16px;
}

View File

@ -355,6 +355,19 @@ protocol.ActorClassWithSpec(serviceWorkerRegistrationSpec, {
"resource://devtools/server/service-worker-child.js", true);
_serviceWorkerProcessScriptLoaded = true;
}
// XXX: Send the permissions down to the content process before starting
// the service worker within the content process. As we don't know what
// content process we're starting the service worker in (as we're using a
// broadcast channel to talk to it), we just broadcast the permissions to
// everyone as well.
//
// This call should be replaced with a proper implementation when
// ServiceWorker debugging is improved to support multiple content processes
// correctly.
Services.perms.broadcastPermissionsForPrincipalToAllContentProcesses(
this._registration.principal);
Services.ppmm.broadcastAsyncMessage("serviceWorkerRegistration:start", {
scope: this._registration.scope
});

View File

@ -550,15 +550,6 @@ CustomElementRegistry::Define(const nsAString& aName,
const ElementDefinitionOptions& aOptions,
ErrorResult& aRv)
{
// We do this for [CEReaction] temporarily and it will be removed
// after webidl supports [CEReaction] annotation in bug 1309147.
DocGroup* docGroup = mWindow->GetDocGroup();
if (!docGroup) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return;
}
AutoCEReaction ceReaction(docGroup->CustomElementReactionsStack());
aRv.MightThrowJSException();
AutoJSAPI jsapi;
@ -918,7 +909,11 @@ CustomElementReactionsStack::PopAndInvokeElementQueue()
"Reaction stack shouldn't be empty");
ElementQueue& elementQueue = mReactionsStack.LastElement();
InvokeReactions(elementQueue);
// Check element queue size in order to reduce function call overhead.
if (!elementQueue.IsEmpty()) {
InvokeReactions(elementQueue);
}
DebugOnly<bool> isRemovedElement = mReactionsStack.RemoveElement(elementQueue);
MOZ_ASSERT(isRemovedElement,
"Reaction stack should have an element queue to remove");
@ -967,7 +962,10 @@ CustomElementReactionsStack::Enqueue(Element* aElement,
void
CustomElementReactionsStack::InvokeBackupQueue()
{
InvokeReactions(mBackupQueue);
// Check backup queue size in order to reduce function call overhead.
if (!mBackupQueue.IsEmpty()) {
InvokeReactions(mBackupQueue);
}
}
void

View File

@ -180,7 +180,8 @@ public:
// nsWeakPtr is a weak pointer of Element
// The element reaction queues are stored in ElementReactionQueueMap.
// We need to lookup ElementReactionQueueMap again to get relevant reaction queue.
typedef nsTArray<nsWeakPtr> ElementQueue;
// The choice of 1 for the auto size here is based on gut feeling.
typedef AutoTArray<nsWeakPtr, 1> ElementQueue;
/**
* Enqueue a custom element upgrade reaction
@ -202,13 +203,19 @@ public:
private:
~CustomElementReactionsStack() {};
typedef nsTArray<nsAutoPtr<CustomElementReaction>> ReactionQueue;
// There is 1 reaction in reaction queue, when 1) it becomes disconnected,
// 2) its adopted into a new document, 3) its attributes are changed,
// appended, removed, or replaced.
// There are 3 reactions in reaction queue when doing upgrade operation,
// e.g., create an element, insert a node.
typedef AutoTArray<nsAutoPtr<CustomElementReaction>, 3> ReactionQueue;
typedef nsClassHashtable<nsISupportsHashKey, ReactionQueue>
ElementReactionQueueMap;
ElementReactionQueueMap mElementReactionQueueMap;
nsTArray<ElementQueue> mReactionsStack;
// The choice of 8 for the auto size here is based on gut feeling.
AutoTArray<ElementQueue, 8> mReactionsStack;
ElementQueue mBackupQueue;
// https://html.spec.whatwg.org/#enqueue-an-element-on-the-appropriate-element-queue
bool mIsBackupQueueProcessing;

View File

@ -6140,6 +6140,7 @@ nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
return;
}
AutoCEReaction ceReaction(this->GetDocGroup()->CustomElementReactionsStack());
// Unconditionally convert TYPE to lowercase.
nsAutoString lcType;
nsContentUtils::ASCIIToLower(aType, lcType);

View File

@ -60,6 +60,7 @@
#include "nsDOMClassInfo.h"
#include "ipc/ErrorIPCUtils.h"
#include "mozilla/UseCounter.h"
#include "mozilla/dom/DocGroup.h"
namespace mozilla {
namespace dom {
@ -3397,6 +3398,28 @@ GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs,
return true;
}
CustomElementReactionsStack*
GetCustomElementReactionsStack(JS::Handle<JSObject*> aObj)
{
// This might not be the right object, if there are wrappers. Unwrap if we can.
JSObject* obj = js::CheckedUnwrap(aObj);
if (!obj) {
return nullptr;
}
nsGlobalWindow* window = xpc::WindowGlobalOrNull(obj);
if (!window) {
return nullptr;
}
DocGroup* docGroup = window->AsInner()->GetDocGroup();
if (!docGroup) {
return nullptr;
}
return docGroup->CustomElementReactionsStack();
}
// https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor
already_AddRefed<nsGenericHTMLElement>
CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,

View File

@ -49,6 +49,7 @@ namespace mozilla {
enum UseCounter : int16_t;
namespace dom {
class CustomElementReactionsStack;
template<typename KeyType, typename ValueType> class Record;
nsresult
@ -3196,6 +3197,12 @@ bool
GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs,
JS::MutableHandle<JSObject*> aDesiredProto);
// Get the CustomElementReactionsStack for the docgroup of the global
// of the underlying object of aObj. This can be null if aObj can't
// be CheckUnwrapped, or if the global of the result has no docgroup
// (e.g. because it's not a Window global).
CustomElementReactionsStack*
GetCustomElementReactionsStack(JS::Handle<JSObject*> aObj);
// This function is expected to be called from the constructor function for an
// HTML element interface; the global/callargs need to be whatever was passed to
// that constructor function.

View File

@ -1691,6 +1691,10 @@ DOMInterfaces = {
'register': False,
},
'TestCEReactionsInterface' : {
'headerFile': 'TestBindingHeader.h',
'register': False,
},
}
# These are temporary, until they've been converted to use new DOM bindings

View File

@ -7502,7 +7502,7 @@ class CGPerSignatureCall(CGThing):
def __init__(self, returnType, arguments, nativeMethodName, static,
descriptor, idlNode, argConversionStartsAt=0, getter=False,
setter=False, isConstructor=False, useCounterName=None,
resultVar=None):
resultVar=None, objectName="obj"):
assert idlNode.isMethod() == (not getter and not setter)
assert idlNode.isAttr() == (getter or setter)
# Constructors are always static
@ -7701,6 +7701,17 @@ class CGPerSignatureCall(CGThing):
CGIfWrapper(CGList(xraySteps),
"objIsXray"))
if (idlNode.getExtendedAttribute('CEReactions') is not None and
not getter):
cgThings.append(CGGeneric(fill(
"""
CustomElementReactionsStack* reactionsStack = GetCustomElementReactionsStack(${obj});
Maybe<AutoCEReaction> ceReaction;
if (reactionsStack) {
ceReaction.emplace(reactionsStack);
}
""", obj=objectName)))
# If this is a method that was generated by a maplike/setlike
# interface, use the maplike/setlike generator to fill in the body.
# Otherwise, use CGCallGenerator to call the native method.
@ -11208,7 +11219,8 @@ class CGProxySpecialOperation(CGPerSignatureCall):
# CGPerSignatureCall won't do any argument conversion of its own.
CGPerSignatureCall.__init__(self, returnType, arguments, nativeName,
False, descriptor, operation,
len(arguments), resultVar=resultVar)
len(arguments), resultVar=resultVar,
objectName="proxy")
if operation.isSetter() or operation.isCreator():
# arguments[0] is the index or name of the item that we're setting.
@ -13996,12 +14008,18 @@ class CGBindingRoot(CGThing):
iface = desc.interface
return any(m.getExtendedAttribute("Deprecated") for m in iface.members + [iface])
def descriptorHasCEReactions(desc):
iface = desc.interface
return any(m.getExtendedAttribute("CEReactions") for m in iface.members + [iface])
bindingHeaders["nsIDocument.h"] = any(
descriptorDeprecated(d) for d in descriptors)
bindingHeaders["mozilla/Preferences.h"] = any(
descriptorRequiresPreferences(d) for d in descriptors)
bindingHeaders["mozilla/dom/DOMJSProxyHandler.h"] = any(
d.concrete and d.proxy for d in descriptors)
bindingHeaders["mozilla/dom/CustomElementRegistry.h"] = any(
descriptorHasCEReactions(d) for d in descriptors)
def descriptorHasChromeOnly(desc):
ctor = desc.interface.ctor()

View File

@ -4097,6 +4097,11 @@ class IDLAttribute(IDLInterfaceMember):
raise WebIDLError("Attribute returns a type that is not exposed "
"everywhere where the attribute is exposed",
[self.location])
if self.getExtendedAttribute("CEReactions"):
if self.readonly:
raise WebIDLError("[CEReactions] is not allowed on "
"readonly attributes",
[self.location])
def handleExtendedAttribute(self, attr):
identifier = attr.identifier()
@ -4283,6 +4288,10 @@ class IDLAttribute(IDLInterfaceMember):
raise WebIDLError("[Unscopable] is only allowed on non-static "
"attributes and operations",
[attr.location, self.location])
elif identifier == "CEReactions":
if not attr.noArguments():
raise WebIDLError("[CEReactions] must take no arguments",
[attr.location])
elif (identifier == "Pref" or
identifier == "Deprecated" or
identifier == "SetterThrows" or
@ -5016,6 +5025,15 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
raise WebIDLError("[Unscopable] is only allowed on non-static "
"attributes and operations",
[attr.location, self.location])
elif identifier == "CEReactions":
if not attr.noArguments():
raise WebIDLError("[CEReactions] must take no arguments",
[attr.location])
if self.isSpecial() and not self.isSetter() and not self.isDeleter():
raise WebIDLError("[CEReactions] is only allowed on operation, "
"attribute, setter, and deleter",
[attr.location, self.location])
elif (identifier == "Throws" or
identifier == "CanOOM" or
identifier == "NewObject" or

View File

@ -0,0 +1,162 @@
def WebIDLTest(parser, harness):
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions(DOMString a)] void foo(boolean arg2);
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Should have thrown for [CEReactions] with an argument")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions(DOMString b)] readonly attribute boolean bar;
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Should have thrown for [CEReactions] with an argument")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions] attribute boolean bar;
};
""")
results = parser.finish()
except Exception, e:
harness.ok(False, "Shouldn't have thrown for [CEReactions] used on writable attribute. %s" % e)
threw = True
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions] void foo(boolean arg2);
};
""")
results = parser.finish()
except Exception, e:
harness.ok(False, "Shouldn't have thrown for [CEReactions] used on regular operations. %s" % e)
threw = True
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions] readonly attribute boolean A;
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Should have thrown for [CEReactions] used on a readonly attribute")
parser = parser.reset()
threw = False
try:
parser.parse("""
[CEReactions]
interface Foo {
}
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Should have thrown for [CEReactions] used on a interface")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions] getter any(DOMString name);
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw,
"Should have thrown for [CEReactions] used on a named getter")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions] creator boolean (DOMString name, boolean value);
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw,
"Should have thrown for [CEReactions] used on a named creator")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions] legacycaller double compute(double x);
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw,
"Should have thrown for [CEReactions] used on a legacycaller")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions] stringifier DOMString ();
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw,
"Should have thrown for [CEReactions] used on a stringifier")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions] jsonifier;
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Should have thrown for [CEReactions] used on a jsonifier")

View File

@ -964,6 +964,11 @@ public:
void NeedsCallerTypeMethod(CallerType);
bool NeedsCallerTypeAttr(CallerType);
void SetNeedsCallerTypeAttr(bool, CallerType);
void CeReactionsMethod();
void CeReactionsMethodOverload();
void CeReactionsMethodOverload(const nsAString&);
bool CeReactionsAttr() const;
void SetCeReactionsAttr(bool);
int16_t LegacyCall(const JS::Value&, uint32_t, TestInterface&);
void PassArgsWithDefaults(JSContext*, const Optional<int32_t>&,
TestInterface*, const Dict&, double,
@ -1456,6 +1461,25 @@ public:
virtual nsISupports* GetParentObject();
};
class TestCEReactionsInterface : public nsISupports,
public nsWrapperCache
{
public:
NS_DECL_ISUPPORTS
// We need a GetParentObject to make binding codegen happy
virtual nsISupports* GetParentObject();
int32_t Item(uint32_t);
uint32_t Length() const;
int32_t IndexedGetter(uint32_t, bool &);
void IndexedSetter(uint32_t, int32_t);
void NamedDeleter(const nsAString&, bool &);
void NamedGetter(const nsAString&, bool &, nsString&);
void NamedSetter(const nsAString&, const nsAString&);
void GetSupportedNames(nsTArray<nsString>&);
};
} // namespace dom
} // namespace mozilla

View File

@ -957,6 +957,10 @@ interface TestInterface {
[NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr;
[NeedsCallerType] void needsCallerTypeMethod();
[NeedsCallerType] attribute boolean needsCallerTypeAttr;
[CEReactions] void ceReactionsMethod();
[CEReactions] void ceReactionsMethodOverload();
[CEReactions] void ceReactionsMethodOverload(DOMString bar);
[CEReactions] attribute boolean ceReactionsAttr;
legacycaller short(unsigned long arg1, TestInterface arg2);
void passArgsWithDefaults(optional long arg1,
optional TestInterface? arg2 = null,
@ -1290,3 +1294,12 @@ interface TestWorkerExposedInterface {
[HTMLConstructor]
interface TestHTMLConstructorInterface {
};
interface TestCEReactionsInterface {
[CEReactions] setter creator void (unsigned long index, long item);
[CEReactions] setter creator void (DOMString name, DOMString item);
[CEReactions] deleter void (DOMString name);
getter long item(unsigned long index);
getter DOMString (DOMString name);
readonly attribute unsigned long length;
};

View File

@ -785,6 +785,10 @@ interface TestExampleInterface {
[NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr;
[NeedsCallerType] void needsCallerTypeMethod();
[NeedsCallerType] attribute boolean needsCallerTypeAttr;
[CEReactions] void ceReactionsMethod();
[CEReactions] void ceReactionsMethodOverload();
[CEReactions] void ceReactionsMethodOverload(DOMString bar);
[CEReactions] attribute boolean ceReactionsAttr;
legacycaller short(unsigned long arg1, TestInterface arg2);
void passArgsWithDefaults(optional long arg1,
optional TestInterface? arg2 = null,

View File

@ -801,6 +801,10 @@ interface TestJSImplInterface {
[CanOOM] attribute boolean canOOMAttr;
[GetterCanOOM] attribute boolean canOOMGetterAttr;
[SetterCanOOM] attribute boolean canOOMSetterAttr;
[CEReactions] void ceReactionsMethod();
[CEReactions] void ceReactionsMethodOverload();
[CEReactions] void ceReactionsMethodOverload(DOMString bar);
[CEReactions] attribute boolean ceReactionsAttr;
// NeedsSubjectPrincipal not supported on JS-implemented things for
// now, because we always pass in the caller principal anyway.
// [NeedsSubjectPrincipal] void needsSubjectPrincipalMethod();

View File

@ -732,6 +732,9 @@ private:
MOZ_ASSERT(argumentsValue.isObject());
JS::Rooted<JSObject*> argumentsObj(aCx, &argumentsValue.toObject());
if (NS_WARN_IF(!argumentsObj)) {
return;
}
uint32_t length;
if (!JS_GetArrayLength(aCx, argumentsObj, &length)) {
@ -1010,6 +1013,8 @@ Console::TimeStamp(const GlobalObject& aGlobal,
{
JSContext* cx = aGlobal.Context();
ClearException ce(cx);
Sequence<JS::Value> data;
SequenceRooter<JS::Value> rooter(cx, &data);
@ -1306,10 +1311,13 @@ Console::MethodInternal(JSContext* aCx, MethodName aMethodName,
? JS_GetEmptyStringValue(aCx)
: aData[0]);
JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
if (!jsString) {
return;
}
nsAutoJSString key;
if (jsString) {
key.init(aCx, jsString);
if (!key.init(aCx, jsString)) {
return;
}
timelines->AddMarkerForDocShell(docShell, Move(
@ -1319,16 +1327,19 @@ Console::MethodInternal(JSContext* aCx, MethodName aMethodName,
else if (isTimelineRecording && aData.Length() == 1) {
JS::Rooted<JS::Value> value(aCx, aData[0]);
JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
if (jsString) {
nsAutoJSString key;
if (key.init(aCx, jsString)) {
timelines->AddMarkerForDocShell(docShell, Move(
MakeUnique<ConsoleTimelineMarker>(
key, aMethodName == MethodTime ? MarkerTracingType::START
: MarkerTracingType::END)));
}
if (!jsString) {
return;
}
nsAutoJSString key;
if (!key.init(aCx, jsString)) {
return;
}
timelines->AddMarkerForDocShell(docShell, Move(
MakeUnique<ConsoleTimelineMarker>(
key, aMethodName == MethodTime ? MarkerTracingType::START
: MarkerTracingType::END)));
}
} else {
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();

View File

@ -2164,7 +2164,7 @@ ContentEventHandler::OnQueryTextRect(WidgetQueryContentEvent* aEvent)
}
// Look for the last frame which should be included text rects.
ErrorResult erv;
IgnoredErrorResult erv;
range->SelectNodeContents(*mRootContent, erv);
if (NS_WARN_IF(erv.Failed())) {
return NS_ERROR_UNEXPECTED;

View File

@ -627,7 +627,9 @@ SerializeInputStreamInChunks(nsIInputStream* aInputStream, uint64_t aLength,
MOZ_ASSERT(aInputStream);
PMemoryStreamChild* child = aManager->SendPMemoryStreamConstructor(aLength);
MOZ_ASSERT(child);
if (NS_WARN_IF(!child)) {
return nullptr;
}
const uint64_t kMaxChunk = 1024 * 1024;
@ -658,7 +660,9 @@ SerializeInputStreamInChunks(nsIInputStream* aInputStream, uint64_t aLength,
return nullptr;
}
child->SendAddChunk(buffer);
if (NS_WARN_IF(!child->SendAddChunk(buffer))) {
return nullptr;
}
}
return child;

View File

@ -5,7 +5,7 @@
// https://html.spec.whatwg.org/#dom-window-customelements
[Func="CustomElementRegistry::IsCustomElementEnabled"]
interface CustomElementRegistry {
[Throws]
[CEReactions, Throws]
void define(DOMString name, Function functionConstructor,
optional ElementDefinitionOptions options);
any get(DOMString name);

View File

@ -3089,3 +3089,16 @@ nsPermissionManager::GetAllKeysForPrincipal(nsIPrincipal* aPrincipal)
"Every principal should have at least one key.");
return keys;
}
NS_IMETHODIMP
nsPermissionManager::BroadcastPermissionsForPrincipalToAllContentProcesses(nsIPrincipal* aPrincipal)
{
nsTArray<ContentParent*> cps;
ContentParent::GetAll(cps);
for (ContentParent* cp : cps) {
nsresult rv = cp->TransmitPermissionsForPrincipal(aPrincipal);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}

View File

@ -18,6 +18,7 @@ using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h
using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h";
using mozilla::wr::ByteBuffer from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::ImageKey from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::FontKey from "mozilla/webrender/WebRenderTypes.h";
using WrBuiltDisplayListDescriptor from "mozilla/webrender/webrender_ffi.h";
using WrAuxiliaryListsDescriptor from "mozilla/webrender/webrender_ffi.h";

View File

@ -9,25 +9,7 @@ include LayersSurfaces;
include LayersMessages;
include protocol PTexture;
using WrBorderRadius from "mozilla/webrender/webrender_ffi.h";
using WrBorderSide from "mozilla/webrender/webrender_ffi.h";
using WrColor from "mozilla/webrender/webrender_ffi.h";
using WrSize from "mozilla/webrender/webrender_ffi.h";
using WrRect from "mozilla/webrender/webrender_ffi.h";
using WrPoint from "mozilla/webrender/webrender_ffi.h";
using WrGradientStop from "mozilla/webrender/webrender_ffi.h";
using WrGradientExtendMode from "mozilla/webrender/webrender_ffi.h";
using WrGlyphArray from "mozilla/webrender/webrender_ffi.h";
using WrMixBlendMode from "mozilla/webrender/webrender_ffi.h";
using WrBoxShadowClipMode from "mozilla/webrender/webrender_ffi.h";
using MaybeImageMask from "mozilla/webrender/WebRenderTypes.h";
using mozilla::gfx::Matrix4x4 from "mozilla/gfx/Matrix.h";
using mozilla::wr::ByteBuffer from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::PipelineId from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::ImageRendering from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::ImageKey from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::FontKey from "mozilla/webrender/WebRenderTypes.h";
using mozilla::LayerIntRegion from "Units.h";
namespace mozilla {
namespace layers {

View File

@ -632,7 +632,7 @@ MessageChannel::CanSend() const
void
MessageChannel::WillDestroyCurrentMessageLoop()
{
#if !defined(ANDROID)
#if defined(DEBUG) && !defined(ANDROID)
#if defined(MOZ_CRASHREPORTER)
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProtocolName"),
nsDependentCString(mName));

View File

@ -100,11 +100,15 @@ function RequireObjectCoercible(v) {
/* Spec: ECMAScript Draft, 6 edition May 22, 2014, 7.1.15 */
function ToLength(v) {
// Step 1.
v = ToInteger(v);
if (v <= 0)
return 0;
// Step 2.
// Use max(v, 0) here, because it's easier to optimize in Ion.
// This is correct even for -0.
v = std_Math_max(v, 0);
// Step 3.
// Math.pow(2, 53) - 1 = 0x1fffffffffffff
return std_Math_min(v, 0x1fffffffffffff);
}

View File

@ -0,0 +1,25 @@
var arrays = [
[],
[1],
[1, 2],
[1, 2, 3],
[1, 2, 3, 4],
];
function test() {
for (var i = 0; i < arrays.length; i++) {
var array = arrays[i];
assertEq(Math.max(array.length, 0), i);
assertEq(Math.max(0, array.length), i);
assertEq(Math.max(array.length, -1), i);
assertEq(Math.max(-1, array.length), i);
assertEq(Math.max(array.length, -1.5), i);
assertEq(Math.max(-1.5, array.length), i);
}
}
test();
test();

View File

@ -0,0 +1,13 @@
let ToLength = getSelfHostedValue('ToLength');
assertEq(ToLength(NaN), 0);
assertEq(ToLength(-0), 0);
assertEq(ToLength(0), 0);
assertEq(ToLength(-Infinity), 0);
assertEq(ToLength(-Math.pow(2, 31)), 0);
const MAX = Math.pow(2, 53) - 1;
assertEq(ToLength(Infinity), MAX);
assertEq(ToLength(MAX + 1), MAX);
assertEq(ToLength(3), 3);
assertEq(ToLength(40.5), 40);

View File

@ -3366,6 +3366,16 @@ MMinMax::foldsTo(TempAllocator& alloc)
return toDouble;
}
}
if (operand->isArrayLength() && constant->type() == MIRType::Int32) {
MOZ_ASSERT(operand->type() == MIRType::Int32);
// max(array.length, 0) = array.length
// ArrayLength is always >= 0, so just return it.
if (isMax() && constant->toInt32() <= 0)
return operand;
}
return this;
}

View File

@ -93,6 +93,9 @@ ReflowInput::ReflowInput(nsPresContext* aPresContext,
if (aFlags & B_CLAMP_MARGIN_BOX_MIN_SIZE) {
mFlags.mBClampMarginBoxMinSize = true;
}
if (aFlags & I_APPLY_AUTO_MIN_SIZE) {
mFlags.mApplyAutoMinSize = true;
}
if (!(aFlags & CALLER_WILL_INIT)) {
Init(aPresContext);
@ -242,6 +245,7 @@ ReflowInput::ReflowInput(
mFlags.mIOffsetsNeedCSSAlign = mFlags.mBOffsetsNeedCSSAlign = false;
mFlags.mIClampMarginBoxMinSize = !!(aFlags & I_CLAMP_MARGIN_BOX_MIN_SIZE);
mFlags.mBClampMarginBoxMinSize = !!(aFlags & B_CLAMP_MARGIN_BOX_MIN_SIZE);
mFlags.mApplyAutoMinSize = !!(aFlags & I_APPLY_AUTO_MIN_SIZE);
mDiscoveredClearance = nullptr;
mPercentBSizeObserver = (aParentReflowInput.mPercentBSizeObserver &&
@ -1666,6 +1670,10 @@ ReflowInput::InitAbsoluteConstraints(nsPresContext* aPresContext,
computeSizeFlags = ComputeSizeFlags(computeSizeFlags |
ComputeSizeFlags::eBClampMarginBoxMinSize);
}
if (mFlags.mApplyAutoMinSize) {
computeSizeFlags = ComputeSizeFlags(computeSizeFlags |
ComputeSizeFlags::eIApplyAutoMinSize);
}
if (mFlags.mShrinkWrap) {
computeSizeFlags =
ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap);
@ -2379,6 +2387,10 @@ ReflowInput::InitConstraints(nsPresContext* aPresContext,
computeSizeFlags = ComputeSizeFlags(computeSizeFlags |
ComputeSizeFlags::eBClampMarginBoxMinSize);
}
if (mFlags.mApplyAutoMinSize) {
computeSizeFlags = ComputeSizeFlags(computeSizeFlags |
ComputeSizeFlags::eIApplyAutoMinSize);
}
if (mFlags.mShrinkWrap) {
computeSizeFlags =
ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap);

View File

@ -220,6 +220,7 @@ public:
bool mStaticPosIsCBOrigin : 1; // the STATIC_POS_IS_CB_ORIGIN ctor flag
bool mIClampMarginBoxMinSize : 1; // the I_CLAMP_MARGIN_BOX_MIN_SIZE ctor flag
bool mBClampMarginBoxMinSize : 1; // the B_CLAMP_MARGIN_BOX_MIN_SIZE ctor flag
bool mApplyAutoMinSize : 1; // the I_APPLY_AUTO_MIN_SIZE ctor flag
// If set, the following two flags indicate that:
// (1) this frame is absolutely-positioned (or fixed-positioned).
@ -739,6 +740,9 @@ public:
// Pass ComputeSizeFlags::eBClampMarginBoxMinSize to ComputeSize().
B_CLAMP_MARGIN_BOX_MIN_SIZE = (1<<6),
// Pass ComputeSizeFlags::eIApplyAutoMinSize to ComputeSize().
I_APPLY_AUTO_MIN_SIZE = (1<<7),
};
// This method initializes various data members. It is automatically

View File

@ -866,8 +866,8 @@ nsContainerFrame::ComputeAutoSize(nsRenderingContext* aRenderingContext,
void
nsContainerFrame::ReflowChild(nsIFrame* aKidFrame,
nsPresContext* aPresContext,
ReflowOutput& aDesiredSize,
const ReflowInput& aReflowInput,
ReflowOutput& aDesiredSize,
const ReflowInput& aReflowInput,
const WritingMode& aWM,
const LogicalPoint& aPos,
const nsSize& aContainerSize,
@ -880,6 +880,9 @@ nsContainerFrame::ReflowChild(nsIFrame* aKidFrame,
NS_ASSERTION(aContainerSize.width != NS_UNCONSTRAINEDSIZE,
"ReflowChild with unconstrained container width!");
}
MOZ_ASSERT(aDesiredSize.VisualOverflow() == nsRect(0,0,0,0) &&
aDesiredSize.ScrollableOverflow() == nsRect(0,0,0,0),
"please reset the overflow areas before calling ReflowChild");
// Position the child frame and its view if requested.
if (NS_FRAME_NO_MOVE_FRAME != (aFlags & NS_FRAME_NO_MOVE_FRAME)) {

View File

@ -5071,7 +5071,7 @@ nsFrame::ComputeSize(nsRenderingContext* aRenderingContext,
ComputeISizeValue(aRenderingContext, aCBSize.ISize(aWM),
boxSizingAdjust.ISize(aWM), boxSizingToMarginEdgeISize,
minISizeCoord, aFlags);
} else if (MOZ_UNLIKELY(isGridItem)) {
} else if (MOZ_UNLIKELY(aFlags & eIApplyAutoMinSize)) {
// This implements "Implied Minimum Size of Grid Items".
// https://drafts.csswg.org/css-grid/#min-size-auto
minISize = std::min(maxISize, GetMinISize(aRenderingContext));

View File

@ -341,6 +341,7 @@ nsHTMLScrollFrame::TryLayout(ScrollReflowInput* aState,
nsLayoutUtils::MarkIntrinsicISizesDirtyIfDependentOnBSize(
mHelper.mScrolledFrame);
}
aKidMetrics->mOverflowAreas.Clear();
ReflowScrolledFrame(aState, aAssumeHScroll, aAssumeVScroll, aKidMetrics,
false);
}
@ -694,6 +695,7 @@ nsHTMLScrollFrame::ReflowContents(ScrollReflowInput* aState,
insideBorderSize);
if (nsRect(nsPoint(0, 0), insideBorderSize).Contains(scrolledRect)) {
// Let's pretend we had no scrollbars coming in here
kidDesiredSize.mOverflowAreas.Clear();
ReflowScrolledFrame(aState, false, false, &kidDesiredSize, false);
}
}

View File

@ -573,8 +573,11 @@ struct nsGridContainerFrame::GridItemInfo
// Ditto *-content:[last ]baseline. Mutually exclusive w. eSelfBaseline.
eContentBaseline = 0x10,
eAllBaselineBits = eIsBaselineAligned | eSelfBaseline | eContentBaseline,
// Should apply Automatic Minimum Size per:
// https://drafts.csswg.org/css-grid/#min-size-auto
eApplyAutoMinSize = 0x20,
// Clamp per https://drafts.csswg.org/css-grid/#min-size-auto
eClampMarginBoxMinSize = 0x20,
eClampMarginBoxMinSize = 0x40,
};
explicit GridItemInfo(nsIFrame* aFrame,
@ -606,11 +609,11 @@ struct nsGridContainerFrame::GridItemInfo
return aAlign;
}
// Return true if we should we clamp this item's Automatic Minimum Size.
// Return true if we should apply Automatic Minimum Size to this item.
// https://drafts.csswg.org/css-grid/#min-size-auto
bool ShouldClampMinSize(WritingMode aContainerWM,
LogicalAxis aContainerAxis,
nscoord aPercentageBasis) const
bool ShouldApplyAutoMinSize(WritingMode aContainerWM,
LogicalAxis aContainerAxis,
nscoord aPercentageBasis) const
{
const auto pos = mFrame->StylePosition();
const auto& size = aContainerAxis == eLogicalAxisInline ?
@ -3454,8 +3457,11 @@ MeasuringReflow(nsIFrame* aChild,
parent->Properties().Set(
nsContainerFrame::DebugReflowingWithInfiniteISize(), true);
#endif
uint32_t riFlags = ReflowInput::COMPUTE_SIZE_SHRINK_WRAP |
ReflowInput::COMPUTE_SIZE_USE_AUTO_BSIZE;
auto wm = aChild->GetWritingMode();
uint32_t riFlags = ReflowInput::COMPUTE_SIZE_USE_AUTO_BSIZE;
if (aAvailableSize.ISize(wm) == INFINITE_ISIZE_COORD) {
riFlags |= ReflowInput::COMPUTE_SIZE_SHRINK_WRAP;
}
if (aIMinSizeClamp != NS_MAXSIZE) {
riFlags |= ReflowInput::I_CLAMP_MARGIN_BOX_MIN_SIZE;
}
@ -3480,7 +3486,6 @@ MeasuringReflow(nsIFrame* aChild,
ReflowOutput childSize(childRI);
nsReflowStatus childStatus;
const uint32_t flags = NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_SIZE_VIEW;
WritingMode wm = childRI.GetWritingMode();
parent->ReflowChild(aChild, pc, childSize, childRI, wm,
LogicalPoint(wm), nsSize(), flags, childStatus);
parent->FinishReflowChild(aChild, pc, childSize, &childRI, wm,
@ -3742,9 +3747,9 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSizeStep1(
WritingMode wm = aState.mWM;
// Calculate data for "Automatic Minimum Size" clamping, if needed.
bool needed = ((sz.mState & TrackSize::eIntrinsicMinSizing) ||
aConstraint == SizingConstraint::eNoConstraint);
if (needed && TrackSize::IsDefiniteMaxSizing(sz.mState) &&
aGridItem.ShouldClampMinSize(wm, mAxis, aPercentageBasis)) {
aConstraint == SizingConstraint::eNoConstraint) &&
(aGridItem.mState[mAxis] & ItemState::eApplyAutoMinSize);
if (needed && TrackSize::IsDefiniteMaxSizing(sz.mState)) {
if (sz.mState & TrackSize::eIntrinsicMinSizing) {
auto maxCoord = aFunctions.MaxSizingFor(aRange.mStart);
cache.mMinSizeClamp =
@ -4147,6 +4152,14 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
iter.Reset();
for (; !iter.AtEnd(); iter.Next()) {
auto& gridItem = aGridItems[iter.ItemIndex()];
// Check if we need to apply "Automatic Minimum Size" and cache it.
MOZ_ASSERT(!(gridItem.mState[mAxis] & ItemState::eApplyAutoMinSize),
"Why is eApplyAutoMinSize set already?");
if (gridItem.ShouldApplyAutoMinSize(wm, mAxis, aPercentageBasis)) {
gridItem.mState[mAxis] |= ItemState::eApplyAutoMinSize;
}
const GridArea& area = gridItem.mArea;
const LineRange& lineRange = area.*aRange;
uint32_t span = lineRange.Extent();
@ -4172,9 +4185,9 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
CachedIntrinsicSizes cache;
// Calculate data for "Automatic Minimum Size" clamping, if needed.
bool needed = ((state & TrackSize::eIntrinsicMinSizing) ||
aConstraint == SizingConstraint::eNoConstraint);
if (needed && TrackSize::IsDefiniteMaxSizing(state) &&
gridItem.ShouldClampMinSize(wm, mAxis, aPercentageBasis)) {
aConstraint == SizingConstraint::eNoConstraint) &&
(gridItem.mState[mAxis] & ItemState::eApplyAutoMinSize);
if (needed && TrackSize::IsDefiniteMaxSizing(state)) {
nscoord minSizeClamp = 0;
for (auto i = lineRange.mStart, end = lineRange.mEnd; i < end; ++i) {
auto maxCoord = aFunctions.MaxSizingFor(i);
@ -4210,11 +4223,14 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
gridItem.mState[mAxis] |= ItemState::eIsFlexing;
} else if (aConstraint == SizingConstraint::eNoConstraint &&
TrackSize::IsDefiniteMaxSizing(state) &&
gridItem.ShouldClampMinSize(wm, mAxis, aPercentageBasis)) {
(gridItem.mState[mAxis] & ItemState::eApplyAutoMinSize)) {
gridItem.mState[mAxis] |= ItemState::eClampMarginBoxMinSize;
}
}
}
MOZ_ASSERT(!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize) ||
(gridItem.mState[mAxis] & ItemState::eApplyAutoMinSize),
"clamping only applies to Automatic Minimum Size");
}
// Step 2.
@ -4996,6 +5012,9 @@ nsGridContainerFrame::ReflowInFlowChild(nsIFrame* aChild,
} else {
aChild->Properties().Delete(BClampMarginBoxMinSizeProperty());
}
if ((aGridItemInfo->mState[childIAxis] & ItemState::eApplyAutoMinSize)) {
flags |= ReflowInput::I_APPLY_AUTO_MIN_SIZE;
}
}
if (!isConstrainedBSize) {

View File

@ -2250,6 +2250,14 @@ public:
*/
eIClampMarginBoxMinSize = 1 << 2, // clamp in our inline axis
eBClampMarginBoxMinSize = 1 << 3, // clamp in our block axis
/**
* The frame is stretching (per CSS Box Alignment) and doesn't have an
* Automatic Minimum Size in the indicated axis.
* (may be used for both flex/grid items, but currently only used for Grid)
* https://drafts.csswg.org/css-grid/#min-size-auto
* https://drafts.csswg.org/css-align-3/#valdef-justify-self-stretch
*/
eIApplyAutoMinSize = 1 << 4, // only has an effect when eShrinkWrap is false
};
/**

View File

@ -0,0 +1,34 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>Testcase for bug 1349571</title>
<style type="text/css">
html,body {
color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
}
.container {
display: grid;
grid: 250px / 500px;
border: 3px solid;
width: 500px;
}
.responsive-container {
background: lightgrey;
}
</style>
</head>
<body>
<div class="container">
<div class="responsive-container"></div>
</div>
</body>
</html>

View File

@ -0,0 +1,38 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>Testcase for bug 1349571</title>
<style type="text/css">
html,body {
color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
}
.container {
display: grid;
grid-template-columns: 1fr;
border: 3px solid;
width: 500px;
}
.responsive-container {
padding-bottom: 50%;
height: 0;
background: lightgrey;
}
</style>
</head>
<body>
<div class="container">
<div>
<div class="responsive-container"></div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,32 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>Testcase for bug 1350925</title>
<style type="text/css">
html, body, .grid { margin: 0; }
.grid {
display: grid;
overflow: auto;
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div style="height:300px; width:100px">
<div class="grid" style="overflow-x:hidden"><div style="width:10px;height:700px"></div></div>
</div>
<div style="width:300px; height:100px">
<div class="grid" style="overflow-y:hidden"><div style="height:10px;width:700px"></div></div>
</div>
</body>
</html>

View File

@ -0,0 +1,32 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>Testcase for bug 1350925</title>
<style type="text/css">
html, body, .grid { margin: 0; }
.grid {
display: grid;
overflow: auto;
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div style="height:300px; width:100px">
<div class="grid"><div style="width:10px;height:700px"></div></div>
</div>
<div style="width:300px; height:100px">
<div class="grid"><div style="height:10px;width:700px"></div></div>
</div>
</body>
</html>

View File

@ -0,0 +1,25 @@
<!DOCTYPE HTML>
<div style="display: grid; width: 5em;">
<div style="word-wrap: break-word; width: 5em; justify-self:start">
first item with a longlonglongword
</div>
<div>
second item
</div>
</div>
<div style="display: grid; width: 5em;">
<div style="width: 5em; justify-self:start">
first item with a longlonglongword
</div>
<div>
second item
</div>
</div>
<div style="display: grid; width: 5em;">
<div style="word-wrap: break-word; writing-mode:vertical-lr; justify-self:start">
first item with a longlonglongword
</div>
<div>
second item
</div>
</div>

View File

@ -0,0 +1,25 @@
<!DOCTYPE HTML>
<div style="display: grid; width: 5em;">
<div style="word-wrap: break-word; min-width: 0;">
first item with a longlonglongword
</div>
<div>
second item
</div>
</div>
<div style="display: grid; width: 5em;">
<div style="min-width: 0;">
first item with a longlonglongword
</div>
<div>
second item
</div>
</div>
<div style="display: grid; width: 5em;">
<div style="word-wrap: break-word; min-height: 0; writing-mode:vertical-lr">
first item with a longlonglongword
</div>
<div>
second item
</div>
</div>

View File

@ -0,0 +1,78 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>CSS Grid Reference: stretching overflow!=visible items</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1348857">
<style type="text/css">
body,html { color:black; background:white; font:16px/1 monospace; padding:0; margin:0; }
.grid {
display: inline-grid;
width: 100px;
height: 50px;
grid: 7px 30px 3px / 7px 80px 3px;
grid-gap: 5px;
border:1px solid;
}
.grid > * {
grid-area: 2/2;
border:1px solid;
min-width:0;
min-height:0;
box-sizing: border-box;
}
.oa, .os, .oh { width:80px; height:30px; }
.m.oa, .m.os, .m.oh { width:70px; height:24px; }
.oa { overflow: auto; }
.os { overflow: scroll; }
.oh { overflow: hidden; }
.m { margin: 1px 3px 5px 7px; }
x { display:block; width:110px; height:5px; background:grey; }
.h .grid x { width:5px; height:110px; }
br { clear:both; }
</style>
</head>
<body>
<div class="grid"><span class="oa"><x></x></span></div>
<div class="grid"><span class="os"><x></x></span></div>
<div class="grid"><span class="oh"><x></x></span></div>
<div class="grid"><span class=" " style="width:112px"><x></x></span></div>
<br>
<div class="grid"><span class="m oa"><x></x></span></div>
<div class="grid"><span class="m os"><x></x></span></div>
<div class="grid"><span class="m oh"><x></x></span></div>
<div class="grid"><span class="m " style="width:112px"><x></x></span></div>
<br>
<div class="h">
<div class="grid"><span class="oa"><x></x></span></div>
<div class="grid"><span class="os"><x></x></span></div>
<div class="grid"><span class="oh"><x></x></span></div>
<div class="grid"><span class=" " style="height:112px"><x></x></span></div>
<br>
<div class="grid"><span class="m oa"><x></x></span></div>
<div class="grid"><span class="m os"><x></x></span></div>
<div class="grid"><span class="m oh"><x></x></span></div>
<div class="grid"><span class="m " style="height:112px"><x></x></span></div>
<br>
</div>
</body>
</html>

View File

@ -0,0 +1,74 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>CSS Grid Test: stretching overflow!=visible items</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1348857">
<link rel="match" href="grid-item-overflow-stretch-001-ref.html">
<style type="text/css">
body,html { color:black; background:white; font:16px/1 monospace; padding:0; margin:0; }
.grid {
display: inline-grid;
width: 100px;
height: 50px;
grid: 7px auto 3px / 7px auto 3px;
grid-gap: 5px;
border:1px solid;
}
.grid > * {
grid-area: 2/2;
border:1px solid;
}
.oa { overflow: auto; }
.os { overflow: scroll; }
.oh { overflow: hidden; }
.m { margin: 1px 3px 5px 7px; }
x { display:block; width:110px; height:5px; background:grey; }
.h .grid x { width:5px; height:110px; }
br { clear:both; }
</style>
</head>
<body>
<div class="grid"><span class="oa"><x></x></span></div>
<div class="grid"><span class="os"><x></x></span></div>
<div class="grid"><span class="oh"><x></x></span></div>
<div class="grid"><span class=" "><x></x></span></div>
<br>
<div class="grid"><span class="m oa"><x></x></span></div>
<div class="grid"><span class="m os"><x></x></span></div>
<div class="grid"><span class="m oh"><x></x></span></div>
<div class="grid"><span class="m "><x></x></span></div>
<br>
<div class="h">
<div class="grid"><span class="oa"><x></x></span></div>
<div class="grid"><span class="os"><x></x></span></div>
<div class="grid"><span class="oh"><x></x></span></div>
<div class="grid"><span class=" "><x></x></span></div>
<br>
<div class="grid"><span class="m oa"><x></x></span></div>
<div class="grid"><span class="m os"><x></x></span></div>
<div class="grid"><span class="m oh"><x></x></span></div>
<div class="grid"><span class="m "><x></x></span></div>
<br>
</div>
</body>
</html>

View File

@ -0,0 +1,79 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>CSS Grid Reference: stretching overflow!=visible vertical-rl items</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1348857">
<style type="text/css">
body,html { color:black; background:white; font:16px/1 monospace; padding:0; margin:0; }
.grid {
display: inline-grid;
width: 100px;
height: 50px;
grid: 7px 30px 3px / 7px 80px 3px;
grid-gap: 5px;
border:1px solid;
}
.grid > * {
grid-area: 2/2;
border:1px solid;
writing-mode: vertical-rl;
min-width:0;
min-height:0;
box-sizing: border-box;
}
.oa, .os, .oh { width:80px; height:30px; }
.m.oa, .m.os, .m.oh { width:70px; height:24px; }
.oa { overflow: auto; }
.os { overflow: scroll; }
.oh { overflow: hidden; }
.m { margin: 1px 3px 5px 7px; }
x { display:block; width:110px; height:5px; background:grey; }
.h .grid x { width:5px; height:110px; }
br { clear:both; }
</style>
</head>
<body>
<div class="grid"><span class="oa"><x></x></span></div>
<div class="grid"><span class="os"><x></x></span></div>
<div class="grid"><span class="oh"><x></x></span></div>
<div class="grid"><span class=" " style="width:112px"><x></x></span></div>
<br>
<div class="grid"><span class="m oa"><x></x></span></div>
<div class="grid"><span class="m os"><x></x></span></div>
<div class="grid"><span class="m oh"><x></x></span></div>
<div class="grid"><span class="m " style="width:112px"><x></x></span></div>
<br>
<div class="h">
<div class="grid"><span class="oa"><x></x></span></div>
<div class="grid"><span class="os"><x></x></span></div>
<div class="grid"><span class="oh"><x></x></span></div>
<div class="grid"><span class=" " style="height:112px"><x></x></span></div>
<br>
<div class="grid"><span class="m oa"><x></x></span></div>
<div class="grid"><span class="m os"><x></x></span></div>
<div class="grid"><span class="m oh"><x></x></span></div>
<div class="grid"><span class="m " style="height:112px"><x></x></span></div>
<br>
</div>
</body>
</html>

View File

@ -0,0 +1,75 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>CSS Grid Test: stretching overflow!=visible vertical-rl items</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1348857">
<link rel="match" href="grid-item-overflow-stretch-002-ref.html">
<style type="text/css">
body,html { color:black; background:white; font:16px/1 monospace; padding:0; margin:0; }
.grid {
display: inline-grid;
width: 100px;
height: 50px;
grid: 7px auto 3px / 7px auto 3px;
grid-gap: 5px;
border:1px solid;
}
.grid > * {
grid-area: 2/2;
border:1px solid;
writing-mode: vertical-rl;
}
.oa { overflow: auto; }
.os { overflow: scroll; }
.oh { overflow: hidden; }
.m { margin: 1px 3px 5px 7px; }
x { display:block; width:110px; height:5px; background:grey; }
.h .grid x { width:5px; height:110px; }
br { clear:both; }
</style>
</head>
<body>
<div class="grid"><span class="oa"><x></x></span></div>
<div class="grid"><span class="os"><x></x></span></div>
<div class="grid"><span class="oh"><x></x></span></div>
<div class="grid"><span class=" "><x></x></span></div>
<br>
<div class="grid"><span class="m oa"><x></x></span></div>
<div class="grid"><span class="m os"><x></x></span></div>
<div class="grid"><span class="m oh"><x></x></span></div>
<div class="grid"><span class="m "><x></x></span></div>
<br>
<div class="h">
<div class="grid"><span class="oa"><x></x></span></div>
<div class="grid"><span class="os"><x></x></span></div>
<div class="grid"><span class="oh"><x></x></span></div>
<div class="grid"><span class=" "><x></x></span></div>
<br>
<div class="grid"><span class="m oa"><x></x></span></div>
<div class="grid"><span class="m os"><x></x></span></div>
<div class="grid"><span class="m oh"><x></x></span></div>
<div class="grid"><span class="m "><x></x></span></div>
<br>
</div>
</body>
</html>

View File

@ -0,0 +1,84 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>CSS Grid Reference: margin:auto stretch items</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1348857">
<style type="text/css">
body,html { color:black; background:white; font:16px/1 monospace; padding:0; margin:0; }
.grid {
display: inline-grid;
width: 100px;
height: 50px;
grid: 7px 30px 3px / 7px 112px 3px;
grid-gap: 5px;
border:1px solid;
}
.c2 { grid-template-columns: 7px 122px 3px; }
.h > .grid { grid: 7px 112px 3px / 7px 80px 3px; }
.grid > * {
grid-area: 2/2;
border:1px solid;
margin: 0 auto;
justify-self:start;
align-self:start;
height:28px;
}
.c2 > * { height:22px; }
.h .grid > * {
margin: 10px 0 0 10px;
justify-self:center;
align-self:center;
width:5px;
height:110px;
}
.m { margin: 1px 3px 5px 7px; }
x { display:block; width:110px; height:5px; background:grey; }
.h .grid x { width:5px; height:110px; }
br { clear:both; }
</style>
</head>
<body>
<div class="grid"><span class="oa"><x></x></span></div>
<div class="grid"><span class="os"><x></x></span></div>
<div class="grid"><span class="oh"><x></x></span></div>
<div class="grid"><span class=" "><x></x></span></div>
<br>
<div class="grid c2"><span class="m oa"><x></x></span></div>
<div class="grid c2"><span class="m os"><x></x></span></div>
<div class="grid c2"><span class="m oh"><x></x></span></div>
<div class="grid c2"><span class="m "><x></x></span></div>
<br>
<div class="h">
<div class="grid"><span class="oa"><x></x></span></div>
<div class="grid"><span class="os"><x></x></span></div>
<div class="grid"><span class="oh"><x></x></span></div>
<div class="grid"><span class=" "><x></x></span></div>
<br>
<div class="grid"><span class="m oa"><x></x></span></div>
<div class="grid"><span class="m os"><x></x></span></div>
<div class="grid"><span class="m oh"><x></x></span></div>
<div class="grid"><span class="m "><x></x></span></div>
<br>
</div>
</body>
</html>

View File

@ -0,0 +1,75 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>CSS Grid Test: margin:auto stretch items</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1348857">
<link rel="match" href="grid-item-overflow-stretch-003-ref.html">
<style type="text/css">
body,html { color:black; background:white; font:16px/1 monospace; padding:0; margin:0; }
.grid {
display: inline-grid;
width: 100px;
height: 50px;
grid: 7px auto 3px / 7px auto 3px;
grid-gap: 5px;
border:1px solid;
}
.grid > * {
grid-area: 2/2;
border:1px solid;
margin: 0 auto;
}
.h .grid > * {
margin: auto;
}
.m { margin: 1px 3px 5px 7px; }
x { display:block; width:110px; height:5px; background:grey; }
.h .grid x { width:5px; height:110px; }
br { clear:both; }
</style>
</head>
<body>
<div class="grid"><span class="oa"><x></x></span></div>
<div class="grid"><span class="os"><x></x></span></div>
<div class="grid"><span class="oh"><x></x></span></div>
<div class="grid"><span class=" "><x></x></span></div>
<br>
<div class="grid"><span class="m oa"><x></x></span></div>
<div class="grid"><span class="m os"><x></x></span></div>
<div class="grid"><span class="m oh"><x></x></span></div>
<div class="grid"><span class="m "><x></x></span></div>
<br>
<div class="h">
<div class="grid"><span class="oa"><x></x></span></div>
<div class="grid"><span class="os"><x></x></span></div>
<div class="grid"><span class="oh"><x></x></span></div>
<div class="grid"><span class=" "><x></x></span></div>
<br>
<div class="grid"><span class="m oa"><x></x></span></div>
<div class="grid"><span class="m os"><x></x></span></div>
<div class="grid"><span class="m oh"><x></x></span></div>
<div class="grid"><span class="m "><x></x></span></div>
<br>
</div>
</body>
</html>

View File

@ -0,0 +1,88 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>CSS Grid Reference: stretching items</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1348857">
<style type="text/css">
body,html { color:black; background:white; font:16px/1 monospace; padding:0; margin:0; }
.grid {
display: inline-grid;
width: 90px;
height: 50px;
grid: 7px 30px 3px / 7px 102px 3px;
grid-gap: 5px;
border:1px solid;
}
.c2 { grid: 7px 30x 3px / 7px 112px 3px; grid-gap: 5px;}
.c3 { grid: 7px 30x 3px / 7px 70px 3px; grid-gap: 5px;}
.grid > * {
grid-area: 2/2;
border:1px solid;
min-width: 0;
max-width: 100px;
}
.h .grid > * {
min-height: 0;
max-height: 100px;
justify-self:center safe;
align-self:center safe;
}
.h > .grid { grid: 7px 102px 3px / 7px 70px 3px; grid-gap: 5px;}
.h > .grid.c2 { grid: 7px 30px 3px / 7px 70px 3px; grid-gap: 5px;}
.h > .grid.c3 { grid: 7px 108px 3px / 7px 70px 3px; grid-gap: 5px;}
.oa { overflow: auto; }
.p { width: 100%; }
.h .grid > .p { height: 100%; }
.x { width:5px; }
.h .grid > .x { max-height:5px; }
.m { margin: 1px 3px 5px 7px; }
x { display:block; width:110px; height:5px; background:grey; }
.h .grid x { width:5px; height:110px; }
br { clear:both; }
</style>
</head>
<body>
<div class="grid"><span class="p oa"><x></x></span></div>
<div class="grid"><span class="p "><x></x></span></div>
<div class="grid c2"><span class="p x" style="height:5px; margin-left:31.5px; margin-top:11.5px"><x></x></span></div>
<div class="grid c2"><span class=" " style="width:68px"><x></x></span></div>
<br>
<div class="grid c3"><span class="p m oa"><x></x></span></div>
<div class="grid c3"><span class="p m"><x></x></span></div>
<div class="grid c2"><span class="m p x"><x></x></span></div>
<div class="grid c2"><span class="m " style="width:58px"><x></x></span></div>
<br>
<div class="h">
<div class="grid"><span class="p oa"><x></x></span></div>
<div class="grid"><span class="p "><x></x></span></div>
<div class="grid c2"><span class="p x" style=""><x></x></span></div>
<div class="grid c2"><span class=" " style="height:28px; width:68px;"><x></x></span></div>
<br>
<div class="grid c3"><span class="m p oa"><x></x></span></div>
<div class="grid c3"><span class="m p"><x></x></span></div>
<div class="grid c2"><span class="m p x" style="justify-self:start;align-self:start"><x></x></span></div>
<div class="grid c2"><span class="m " style="height:22px; width:58px"><x></x></span></div>
<br>
</div>
</body>
</html>

View File

@ -0,0 +1,82 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>CSS Grid Test: stretching items</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1348857">
<link rel="match" href="grid-item-overflow-stretch-004-ref.html">
<style type="text/css">
body,html { color:black; background:white; font:16px/1 monospace; padding:0; margin:0; }
.grid {
display: inline-grid;
width: 90px;
height: 50px;
grid: 7px auto 3px / 7px auto 3px;
grid-gap: 5px;
border:1px solid;
}
.grid > * {
grid-area: 2/2;
border:1px solid;
min-width: 0;
max-width: 100px;
}
.h .grid > * {
min-height: 0;
max-height: 100px;
}
.oa { overflow: auto; }
.p { width: 100%; }
.h .grid > .p { height: 100%; }
.x { max-width:5px; margin:auto; }
.h .grid > .x { max-height:5px; }
.m { margin: 1px 3px 5px 7px; }
x { display:block; width:110px; height:5px; background:grey; }
.h .grid x { width:5px; height:110px; }
br { clear:both; }
</style>
</head>
<body>
<div class="grid"><span class="p oa"><x></x></span></div>
<div class="grid"><span class="p "><x></x></span></div>
<div class="grid"><span class="p x"><x></x></span></div>
<div class="grid"><span class=" "><x></x></span></div>
<br>
<div class="grid"><span class="p m oa"><x></x></span></div>
<div class="grid"><span class="p m"><x></x></span></div>
<div class="grid"><span class="m p x"><x></x></span></div>
<div class="grid"><span class="m "><x></x></span></div>
<br>
<div class="h">
<div class="grid"><span class="p oa"><x></x></span></div>
<div class="grid"><span class="p "><x></x></span></div>
<div class="grid"><span class="p x"><x></x></span></div>
<div class="grid"><span class=" "><x></x></span></div>
<br>
<div class="grid"><span class="m p oa"><x></x></span></div>
<div class="grid"><span class="m p"><x></x></span></div>
<div class="grid"><span class="m p x"><x></x></span></div>
<div class="grid"><span class="m "><x></x></span></div>
<br>
</div>
</body>
</html>

View File

@ -0,0 +1,83 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>CSS Grid Reference: stretching overflow!=visible items</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1348857">
<style type="text/css">
body,html { color:black; background:white; font:16px/1 monospace; padding:0; margin:0; }
.grid {
display: inline-grid;
width: 100px;
height: 50px;
grid: 7px auto 3px / 7px auto 3px;
grid-gap: 5px;
border:1px solid;
}
.grid > * {
grid-area: 2/2;
border:1px solid;
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
min-width:0;
min-height:0;
box-sizing: border-box;
}
.oa, .os, .oh { width:80px; height:30px; }
.m.oa, .m.os, .m.oh { width:70px; height:8px; }
.oa { overflow: auto; }
.os { overflow: scroll; }
.oh { overflow: hidden; }
.ov { justify-self: start; }
.m.ov { align-self: start; }
.m { margin: 17px 3px 5px 7px; }
x { display:block; width:110px; height:5px; background:grey; }
.h .grid x { width:5px; height:110px; }
br { clear:both; }
</style>
</head>
<body>
<div class="grid"><input class="oa"></div>
<div class="grid"><input class="os"></div>
<div class="grid"><input class="oh"></div>
<div class="grid"><input class="ov"></div>
<br>
<div class="grid"><input class="m oa"></div>
<div class="grid"><input class="m os"></div>
<div class="grid"><input class="m oh"></div>
<div class="grid"><input class="m ov"></div>
<br>
<div class="h">
<div class="grid"><input class="oa"></div>
<div class="grid"><input class="os"></div>
<div class="grid"><input class="oh"></div>
<div class="grid"><input class="ov"></div>
<br>
<div class="grid"><input class="m oa"></div>
<div class="grid"><input class="m os"></div>
<div class="grid"><input class="m oh"></div>
<div class="grid"><input class="m ov"></div>
<br>
</div>
</body>
</html>

View File

@ -0,0 +1,77 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>CSS Grid Test: stretching overflow!=visible items</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1348857">
<link rel="match" href="grid-item-overflow-stretch-005-ref.html">
<style type="text/css">
body,html { color:black; background:white; font:16px/1 monospace; padding:0; margin:0; }
.grid {
display: inline-grid;
width: 100px;
height: 50px;
grid: 7px auto 3px / 7px auto 3px;
grid-gap: 5px;
border:1px solid;
}
.grid > * {
grid-area: 2/2;
border:1px solid;
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
}
.oa { overflow: auto; }
.os { overflow: scroll; }
.oh { overflow: hidden; }
.m { margin: 17px 3px 5px 7px; }
x { display:block; width:110px; height:5px; background:grey; }
.h .grid x { width:5px; height:110px; }
br { clear:both; }
</style>
</head>
<body>
<div class="grid"><input class="oa"></div>
<div class="grid"><input class="os"></div>
<div class="grid"><input class="oh"></div>
<div class="grid"><input class=" "></div>
<br>
<div class="grid"><input class="m oa"></div>
<div class="grid"><input class="m os"></div>
<div class="grid"><input class="m oh"></div>
<div class="grid"><input class="m "></div>
<br>
<div class="h">
<div class="grid"><input class="oa"></div>
<div class="grid"><input class="os"></div>
<div class="grid"><input class="oh"></div>
<div class="grid"><input class=" "></div>
<br>
<div class="grid"><input class="m oa"></div>
<div class="grid"><input class="m os"></div>
<div class="grid"><input class="m oh"></div>
<div class="grid"><input class="m "></div>
<br>
</div>
</body>
</html>

View File

@ -0,0 +1,54 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>CSS Grid Reference: stretching overflow visible items</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1348857">
<style type="text/css">
body,html { color:black; background:white; font:16px/1 monospace; padding:0; margin:0; }
.grid {
display: inline-flex;
width: 90px;
height: 40px;
padding: 7px 3px 3px 7px;
border: 1px solid;
}
.grid > * {
border: 1px solid;
margin: 5px;
}
.m { margin: 6px 8px 10px 12px; }
.ma { margin: auto; }
x { display:block; width:110px; height:5px; background:grey; }
.h .grid x { width:5px; height:110px; }
br { clear:both; }
</style>
</head>
<body>
<div class="grid"><span class=""><x></x></span></div>
<div class="grid"><span class="m"><x></x></span></div>
<div class="grid"><span class="ma" style="margin-left:5px"><x></x></span></div>
<br>
<div class="h">
<div class="grid"><span class="" style="flex:1"><x></x></span></div>
<div class="grid"><span class="m" style="flex:1"><x></x></span></div>
<div class="grid"><span class="ma" style="margin-top:5px"><x></x></span></div>
<br>
</div>
</body>
</html>

View File

@ -0,0 +1,56 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>CSS Grid Test: stretching overflow visible items</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1348857">
<link rel="match" href="grid-item-overflow-stretch-006-ref.html">
<style type="text/css">
body,html { color:black; background:white; font:16px/1 monospace; padding:0; margin:0; }
.grid {
display: inline-grid;
width: 100px;
height: 50px;
grid: 7px minmax(20px, auto) 3px / 7px minmax(20px, auto) 3px;
grid-gap: 5px;
border: 1px solid;
}
.grid > * {
grid-area: 2/2;
border: 1px solid;
}
.m { margin: 1px 3px 5px 7px; }
.ma { margin: auto; }
x { display:block; width:110px; height:5px; background:grey; }
.h .grid x { width:5px; height:110px; }
br { clear:both; }
</style>
</head>
<body>
<div class="grid"><span class=""><x></x></span></div>
<div class="grid"><span class="m"><x></x></span></div>
<div class="grid"><span class="ma"><x></x></span></div>
<br>
<div class="h">
<div class="grid"><span class=""><x></x></span></div>
<div class="grid"><span class="m"><x></x></span></div>
<div class="grid"><span class="ma"><x></x></span></div>
<br>
</div>
</body>
</html>

View File

@ -116,6 +116,12 @@ skip-if(Android) == grid-auto-min-sizing-percent-001.html grid-auto-min-sizing-p
== grid-item-auto-min-size-clamp-005.html grid-item-auto-min-size-clamp-005-ref.html
== grid-item-auto-min-size-clamp-006.html grid-item-auto-min-size-clamp-006-ref.html
== grid-item-auto-min-size-clamp-007.html grid-item-auto-min-size-clamp-007-ref.html
== grid-item-overflow-stretch-001.html grid-item-overflow-stretch-001-ref.html
== grid-item-overflow-stretch-002.html grid-item-overflow-stretch-002-ref.html
== grid-item-overflow-stretch-003.html grid-item-overflow-stretch-003-ref.html
== grid-item-overflow-stretch-004.html grid-item-overflow-stretch-004-ref.html
== grid-item-overflow-stretch-005.html grid-item-overflow-stretch-005-ref.html
== grid-item-overflow-stretch-006.html grid-item-overflow-stretch-006-ref.html
== grid-item-canvas-001.html grid-item-canvas-001-ref.html
skip-if(Android) == grid-item-button-001.html grid-item-button-001-ref.html
== grid-item-table-stretch-001.html grid-item-table-stretch-001-ref.html
@ -277,3 +283,6 @@ asserts(1-10) == grid-fragmentation-dyn4-021.html grid-fragmentation-021-ref.htm
== grid-percent-intrinsic-sizing-001.html grid-percent-intrinsic-sizing-001-ref.html
== grid-measuring-reflow-resize-static-001.html grid-measuring-reflow-resize-001-ref.html
== grid-measuring-reflow-resize-dynamic-001.html grid-measuring-reflow-resize-001-ref.html
== bug1349571.html bug1349571-ref.html
== bug1356820.html bug1356820-ref.html
== bug1350925.html bug1350925-ref.html

View File

@ -1851,6 +1851,10 @@ public class BrowserApp extends GeckoApp
case "Menu:Add":
final MenuItemInfo info = new MenuItemInfo();
info.label = message.getString("name");
if (info.label == null) {
Log.e(LOGTAG, "Invalid menu item name");
return;
}
info.id = message.getInt("id") + ADDON_MENU_OFFSET;
info.checked = message.getBoolean("checked", false);
info.enabled = message.getBoolean("enabled", true);

View File

@ -215,6 +215,7 @@ public class DownloadAction extends BaseAction {
protected void extract(File sourceFile, File destinationFile, String checksum)
throws UnrecoverableDownloadContentException, RecoverableDownloadContentException {
InputStream inputStream = null;
InputStream gzInputStream = null;
OutputStream outputStream = null;
File temporaryFile = null;
@ -226,13 +227,15 @@ public class DownloadAction extends BaseAction {
temporaryFile = new File(destinationDirectory, destinationFile.getName() + ".tmp");
inputStream = new GZIPInputStream(new BufferedInputStream(new FileInputStream(sourceFile)));
// We have to have keep a handle to the BufferedInputStream: the GZIPInputStream
// constructor can fail e.g. if the stream isn't a GZIP stream. If we didn't keep
// a reference to that stream we wouldn't be able to close it if GZInputStream throws.
// (The BufferedInputStream constructor doesn't throw, so we don't need to care about it.)
inputStream = new BufferedInputStream(new FileInputStream(sourceFile));
gzInputStream = new GZIPInputStream(inputStream);
outputStream = new BufferedOutputStream(new FileOutputStream(temporaryFile));
IOUtils.copy(inputStream, outputStream);
inputStream.close();
outputStream.close();
IOUtils.copy(gzInputStream, outputStream);
if (!verify(temporaryFile, checksum)) {
Log.w(LOGTAG, "Checksum of extracted file does not match.");
@ -244,6 +247,7 @@ public class DownloadAction extends BaseAction {
// We could not extract to the destination: Keep temporary file and try again next time we run.
throw new RecoverableDownloadContentException(RecoverableDownloadContentException.DISK_IO, e);
} finally {
IOUtils.safeStreamClose(gzInputStream);
IOUtils.safeStreamClose(inputStream);
IOUtils.safeStreamClose(outputStream);

View File

@ -369,7 +369,6 @@ gvjar.sources += [geckoview_source_dir + 'java/org/mozilla/gecko/' + x
'GeckoSharedPrefs.java',
'GeckoThread.java',
'GeckoView.java',
'GeckoViewChrome.java',
'GeckoViewFragment.java',
'GeckoViewSettings.java',
'gfx/BitmapUtils.java',

View File

@ -0,0 +1,10 @@
# GeckoViewPrompt.js
component {076ac188-23c1-4390-aa08-7ef1f78ca5d9} GeckoViewPrompt.js
contract @mozilla.org/embedcomp/prompt-service;1 {076ac188-23c1-4390-aa08-7ef1f78ca5d9}
contract @mozilla.org/prompter;1 {076ac188-23c1-4390-aa08-7ef1f78ca5d9}
category app-startup GeckoViewPrompt service,@mozilla.org/prompter;1
category profile-after-change GeckoViewPrompt @mozilla.org/prompter;1 process=main
component {aa0dd6fc-73dd-4621-8385-c0b377e02cee} GeckoViewPrompt.js process=main
contract @mozilla.org/colorpicker;1 {aa0dd6fc-73dd-4621-8385-c0b377e02cee} process=main
component {e4565e36-f101-4bf5-950b-4be0887785a9} GeckoViewPrompt.js process=main
contract @mozilla.org/filepicker;1 {e4565e36-f101-4bf5-950b-4be0887785a9} process=main

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,10 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXTRA_COMPONENTS += [
'GeckoView.manifest',
'GeckoViewPrompt.js',
]

View File

@ -50,4 +50,5 @@ EXTRA_PP_COMPONENTS += [
DIRS += [
'extensions',
'build',
'geckoview',
]

View File

@ -6,6 +6,10 @@
package org.mozilla.gecko;
import java.io.File;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Set;
import org.mozilla.gecko.annotation.ReflectionTarget;
@ -17,8 +21,11 @@ import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.GeckoBundle;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@ -64,16 +71,30 @@ public class GeckoView extends LayerView
}
}
static {
EventDispatcher.getInstance().registerUiThreadListener(new BundleEventListener() {
@Override
public void handleMessage(final String event, final GeckoBundle message,
final EventCallback callback) {
if ("GeckoView:Prompt".equals(event)) {
handlePromptEvent(/* view */ null, message, callback);
}
}
}, "GeckoView:Prompt");
}
private static PromptDelegate sDefaultPromptDelegate;
private final NativeQueue mNativeQueue =
new NativeQueue(State.INITIAL, State.READY);
private final EventDispatcher mEventDispatcher =
new EventDispatcher(mNativeQueue);
private ChromeDelegate mChromeDelegate;
/* package */ ContentListener mContentListener;
/* package */ NavigationListener mNavigationListener;
/* package */ ProgressListener mProgressListener;
private PromptDelegate mPromptDelegate;
private InputConnectionListener mInputConnectionListener;
private GeckoViewSettings mSettings;
@ -173,6 +194,7 @@ public class GeckoView extends LayerView
"GeckoView:LocationChange",
"GeckoView:PageStart",
"GeckoView:PageStop",
"GeckoView:Prompt",
"GeckoView:SecurityChanged",
null);
}
@ -205,6 +227,8 @@ public class GeckoView extends LayerView
if (mProgressListener != null) {
mProgressListener.onPageStop(GeckoView.this, message.getBoolean("success"));
}
} else if ("GeckoView:Prompt".equals(event)) {
handlePromptEvent(GeckoView.this, message, callback);
} else if ("GeckoView:SecurityChanged".equals(event)) {
if (mProgressListener != null) {
mProgressListener.onSecurityChange(GeckoView.this, message.getInt("status"));
@ -504,15 +528,6 @@ public class GeckoView extends LayerView
throw new IllegalArgumentException("Must import script from 'resources://android/assets/' location.");
}
/**
* Set the chrome callback handler.
* This will replace the current handler.
* @param chrome An implementation of GeckoViewChrome.
*/
public void setChromeDelegate(ChromeDelegate chrome) {
mChromeDelegate = chrome;
}
/**
* Set the content callback handler.
* This will replace the current handler.
@ -573,6 +588,398 @@ public class GeckoView extends LayerView
return mNavigationListener;
}
/**
* Set the default prompt delegate for all GeckoView instances. The default prompt
* delegate is used for certain types of prompts and for GeckoViews that do not have
* custom prompt delegates.
* @param delegate PromptDelegate instance or null to use the built-in delegate.
* @see #setPromptDelegate(PromptDelegate)
*/
public static void setDefaultPromptDelegate(PromptDelegate delegate) {
sDefaultPromptDelegate = delegate;
}
/**
* Get the default prompt delegate for all GeckoView instances.
* @return PromptDelegate instance
* @see #getPromptDelegate()
*/
public static PromptDelegate getDefaultPromptDelegate() {
return sDefaultPromptDelegate;
}
/**
* Set the current prompt delegate for this GeckoView.
* @param delegate PromptDelegate instance or null to use the default delegate.
* @see #setDefaultPromptDelegate(PromptDelegate)
*/
public void setPromptDelegate(PromptDelegate delegate) {
mPromptDelegate = delegate;
}
/**
* Get the current prompt delegate for this GeckoView.
* @return PromptDelegate instance or null if using default delegate.
* @see #getDefaultPromptDelegate()
*/
public PromptDelegate getPromptDelegate() {
return mPromptDelegate;
}
private static class PromptCallback implements
PromptDelegate.AlertCallback, PromptDelegate.ButtonCallback,
PromptDelegate.TextCallback, PromptDelegate.AuthCallback,
PromptDelegate.ChoiceCallback, PromptDelegate.FileCallback {
private final String mType;
private final String mMode;
private final boolean mHasCheckbox;
private final String mCheckboxMessage;
private EventCallback mCallback;
private boolean mCheckboxValue;
private GeckoBundle mResult;
public PromptCallback(final String type, final String mode,
final GeckoBundle message, final EventCallback callback) {
mType = type;
mMode = mode;
mCallback = callback;
mHasCheckbox = message.getBoolean("hasCheck");
mCheckboxMessage = message.getString("checkMsg");
mCheckboxValue = message.getBoolean("checkValue");
}
private GeckoBundle ensureResult() {
if (mResult == null) {
// Usually result object contains two items.
mResult = new GeckoBundle(2);
}
return mResult;
}
private void submit() {
if (mHasCheckbox) {
ensureResult().putBoolean("checkValue", mCheckboxValue);
}
if (mCallback != null) {
mCallback.sendSuccess(mResult);
mCallback = null;
}
}
@Override // AlertCallbcak
public void dismiss() {
// Send a null result.
mResult = null;
submit();
}
@Override // AlertCallbcak
public boolean hasCheckbox() {
return mHasCheckbox;
}
@Override // AlertCallbcak
public String getCheckboxMessage() {
return mCheckboxMessage;
}
@Override // AlertCallbcak
public boolean getCheckboxValue() {
return mCheckboxValue;
}
@Override // AlertCallbcak
public void setCheckboxValue(final boolean value) {
mCheckboxValue = value;
}
@Override // ButtonCallback
public void confirm(final int value) {
if ("button".equals(mType)) {
ensureResult().putInt("button", value);
} else {
throw new UnsupportedOperationException();
}
submit();
}
@Override // TextCallback, AuthCallback, ChoiceCallback, FileCallback
public void confirm(final String value) {
if ("text".equals(mType) || "color".equals(mType) || "datetime".equals(mType)) {
ensureResult().putString(mType, value);
} else if ("auth".equals(mType)) {
if (!"password".equals(mMode)) {
throw new IllegalArgumentException();
}
ensureResult().putString("password", value);
} else if ("choice".equals(mType)) {
confirm(new String[] { value });
return;
} else {
throw new UnsupportedOperationException();
}
submit();
}
@Override // AuthCallback
public void confirm(final String username, final String password) {
if ("auth".equals(mType)) {
if (!"auth".equals(mMode)) {
throw new IllegalArgumentException();
}
ensureResult().putString("username", username);
ensureResult().putString("password", password);
} else {
throw new UnsupportedOperationException();
}
submit();
}
@Override // ChoiceCallback, FileCallback
public void confirm(final String[] values) {
if (("menu".equals(mMode) || "single".equals(mMode)) &&
(values == null || values.length != 1)) {
throw new IllegalArgumentException();
}
if ("choice".equals(mType)) {
ensureResult().putStringArray("choices", values);
} else {
throw new UnsupportedOperationException();
}
submit();
}
@Override // ChoiceCallback
public void confirm(GeckoBundle item) {
if ("choice".equals(mType)) {
confirm(item == null ? null : item.getString("id"));
return;
} else {
throw new UnsupportedOperationException();
}
}
@Override // ChoiceCallback
public void confirm(GeckoBundle[] items) {
if (("menu".equals(mMode) || "single".equals(mMode)) &&
(items == null || items.length != 1)) {
throw new IllegalArgumentException();
}
if ("choice".equals(mType)) {
if (items == null) {
confirm((String[]) null);
return;
}
final String[] ids = new String[items.length];
for (int i = 0; i < ids.length; i++) {
ids[i] = (items[i] == null) ? null : items[i].getString("id");
}
confirm(ids);
return;
} else {
throw new UnsupportedOperationException();
}
}
@Override // FileCallback
public void confirm(final Uri uri) {
if ("file".equals(mType)) {
confirm(uri == null ? null : new Uri[] { uri });
return;
} else {
throw new UnsupportedOperationException();
}
}
private static String getFile(final Uri uri) {
if (uri == null) {
return null;
}
if ("file".equals(uri.getScheme())) {
return uri.getPath();
}
final ContentResolver cr =
GeckoAppShell.getApplicationContext().getContentResolver();
final Cursor cur = cr.query(uri, new String[] { "_data" }, /* selection */ null,
/* args */ null, /* sort */ null);
if (cur == null) {
return null;
}
try {
final int idx = cur.getColumnIndex("_data");
if (idx < 0 || !cur.moveToFirst()) {
return null;
}
do {
try {
final String path = cur.getString(idx);
if (path != null && !path.isEmpty()) {
return path;
}
} catch (final Exception e) {
}
} while (cur.moveToNext());
} finally {
cur.close();
}
return null;
}
@Override // FileCallback
public void confirm(final Uri[] uris) {
if ("single".equals(mMode) && (uris == null || uris.length != 1)) {
throw new IllegalArgumentException();
}
if ("file".equals(mType)) {
final String[] paths = new String[uris != null ? uris.length : 0];
for (int i = 0; i < paths.length; i++) {
paths[i] = getFile(uris[i]);
if (paths[i] == null) {
Log.e(LOGTAG, "Only file URI is supported: " + uris[i]);
}
}
ensureResult().putStringArray("files", paths);
} else {
throw new UnsupportedOperationException();
}
submit();
}
}
/* package */ static void handlePromptEvent(final GeckoView view,
final GeckoBundle message,
final EventCallback callback) {
final PromptDelegate delegate;
if (view != null && view.mPromptDelegate != null) {
delegate = view.mPromptDelegate;
} else {
delegate = sDefaultPromptDelegate;
}
if (delegate == null) {
// Default behavior is same as calling dismiss() on callback.
callback.sendSuccess(null);
return;
}
final String type = message.getString("type");
final String mode = message.getString("mode");
final PromptCallback cb = new PromptCallback(type, mode, message, callback);
final String title = message.getString("title");
final String msg = message.getString("msg");
switch (type) {
case "alert": {
delegate.alert(view, title, msg, cb);
break;
}
case "button": {
final String[] btnTitle = message.getStringArray("btnTitle");
final String[] btnCustomTitle = message.getStringArray("btnCustomTitle");
for (int i = 0; i < btnCustomTitle.length; i++) {
final int resId;
if ("ok".equals(btnTitle[i])) {
resId = android.R.string.ok;
} else if ("cancel".equals(btnTitle[i])) {
resId = android.R.string.cancel;
} else if ("yes".equals(btnTitle[i])) {
resId = android.R.string.yes;
} else if ("no".equals(btnTitle[i])) {
resId = android.R.string.no;
} else {
continue;
}
btnCustomTitle[i] = Resources.getSystem().getString(resId);
}
delegate.promptForButton(view, title, msg, btnCustomTitle, cb);
break;
}
case "text": {
delegate.promptForText(view, title, msg, message.getString("value"), cb);
break;
}
case "auth": {
delegate.promptForAuth(view, title, msg, message.getBundle("options"), cb);
break;
}
case "choice": {
final int intMode;
if ("menu".equals(mode)) {
intMode = PromptDelegate.CHOICE_TYPE_MENU;
} else if ("single".equals(mode)) {
intMode = PromptDelegate.CHOICE_TYPE_SINGLE;
} else if ("multiple".equals(mode)) {
intMode = PromptDelegate.CHOICE_TYPE_MULTIPLE;
} else {
callback.sendError("Invalid mode");
return;
}
delegate.promptForChoice(view, title, msg, intMode,
message.getBundleArray("choices"), cb);
break;
}
case "color": {
delegate.promptForColor(view, title, message.getString("value"), cb);
break;
}
case "datetime": {
final int intMode;
if ("date".equals(mode)) {
intMode = PromptDelegate.DATETIME_TYPE_DATE;
} else if ("month".equals(mode)) {
intMode = PromptDelegate.DATETIME_TYPE_MONTH;
} else if ("week".equals(mode)) {
intMode = PromptDelegate.DATETIME_TYPE_WEEK;
} else if ("time".equals(mode)) {
intMode = PromptDelegate.DATETIME_TYPE_TIME;
} else if ("datetime-local".equals(mode)) {
intMode = PromptDelegate.DATETIME_TYPE_DATETIME_LOCAL;
} else {
callback.sendError("Invalid mode");
return;
}
delegate.promptForDateTime(view, title, intMode,
message.getString("value"),
message.getString("min"),
message.getString("max"), cb);
break;
}
case "file": {
final int intMode;
if ("single".equals(mode)) {
intMode = PromptDelegate.FILE_TYPE_SINGLE;
} else if ("multiple".equals(mode)) {
intMode = PromptDelegate.FILE_TYPE_MULTIPLE;
} else {
callback.sendError("Invalid mode");
return;
}
String[] mimeTypes = message.getStringArray("mimeTypes");
final String[] extensions = message.getStringArray("extension");
if (extensions != null) {
final ArrayList<String> combined =
new ArrayList<>(mimeTypes.length + extensions.length);
combined.addAll(Arrays.asList(mimeTypes));
for (final String extension : extensions) {
final String mimeType =
URLConnection.guessContentTypeFromName(extension);
if (mimeType != null) {
combined.add(mimeType);
}
}
mimeTypes = combined.toArray(new String[combined.size()]);
}
delegate.promptForFile(view, title, intMode, mimeTypes, cb);
break;
}
default: {
callback.sendError("Invalid type");
break;
}
}
}
public static void setGeckoInterface(final BaseGeckoInterface geckoInterface) {
GeckoAppShell.setGeckoInterface(geckoInterface);
}
@ -594,72 +1001,6 @@ public class GeckoView extends LayerView
return mEventDispatcher;
}
/* Provides a means for the client to indicate whether a JavaScript
* dialog request should proceed. An instance of this class is passed to
* various GeckoViewChrome callback actions.
*/
public class PromptResult {
public PromptResult() {
}
/**
* Handle a confirmation response from the user.
*/
public void confirm() {
}
/**
* Handle a confirmation response from the user.
* @param value String value to return to the browser context.
*/
public void confirmWithValue(String value) {
}
/**
* Handle a cancellation response from the user.
*/
public void cancel() {
}
}
public interface ChromeDelegate {
/**
* Tell the host application to display an alert dialog.
* @param view The GeckoView that initiated the callback.
* @param message The string to display in the dialog.
* @param result A PromptResult used to send back the result without blocking.
* Defaults to cancel requests.
*/
void onAlert(GeckoView view, String message, GeckoView.PromptResult result);
/**
* Tell the host application to display a confirmation dialog.
* @param view The GeckoView that initiated the callback.
* @param message The string to display in the dialog.
* @param result A PromptResult used to send back the result without blocking.
* Defaults to cancel requests.
*/
void onConfirm(GeckoView view, String message, GeckoView.PromptResult result);
/**
* Tell the host application to display an input prompt dialog.
* @param view The GeckoView that initiated the callback.
* @param message The string to display in the dialog.
* @param defaultValue The string to use as default input.
* @param result A PromptResult used to send back the result without blocking.
* Defaults to cancel requests.
*/
void onPrompt(GeckoView view, String message, String defaultValue, GeckoView.PromptResult result);
/**
* Tell the host application to display a remote debugging request dialog.
* @param view The GeckoView that initiated the callback.
* @param result A PromptResult used to send back the result without blocking.
* Defaults to cancel requests.
*/
void onDebugRequest(GeckoView view, GeckoView.PromptResult result);
}
public interface ProgressListener {
static final int STATE_IS_BROKEN = 1;
static final int STATE_IS_SECURE = 2;
@ -719,4 +1060,357 @@ public class GeckoView extends LayerView
*/
void onCanGoForward(GeckoView view, boolean canGoForward);
}
/**
* GeckoView applications implement this interface to handle prompts triggered by
* content in the GeckoView, such as alerts, authentication dialogs, and select list
* pickers.
**/
public interface PromptDelegate {
/**
* Callback interface for notifying the result of a prompt, and for accessing the
* optional features for prompts (e.g. optional checkbox).
*/
interface AlertCallback {
/**
* Called by the prompt implementation when the prompt is dismissed without a
* result, for example if the user presses the "Back" button. All prompts
* must call dismiss() or confirm(), if available, when the prompt is dismissed.
*/
void dismiss();
/**
* Return whether the prompt shown should include a checkbox. For example, if
* a page shows multiple prompts within a short period of time, the next
* prompt will include a checkbox to let the user disable future prompts.
* Although the API allows checkboxes for all prompts, in practice, only
* alert/button/text/auth prompts will possibly have a checkbox.
*/
boolean hasCheckbox();
/**
* Return the message label for the optional checkbox.
*/
String getCheckboxMessage();
/**
* Return the initial value for the optional checkbox.
*/
boolean getCheckboxValue();
/**
* Set the current value for the optional checkbox.
*/
void setCheckboxValue(boolean value);
}
/**
* Display a simple message prompt.
*
* @param view The GeckoView that triggered the prompt
* or null if the prompt is a global prompt.
* @param title Title for the prompt dialog.
* @param msg Message for the prompt dialog.
* @param callback Callback interface.
*/
void alert(GeckoView view, String title, String msg, AlertCallback callback);
/**
* Callback interface for notifying the result of a button prompt.
*/
interface ButtonCallback extends AlertCallback {
/**
* Called by the prompt implementation when the button prompt is dismissed by
* the user pressing one of the buttons.
*/
void confirm(int button);
}
static final int BUTTON_TYPE_POSITIVE = 0;
static final int BUTTON_TYPE_NEUTRAL = 1;
static final int BUTTON_TYPE_NEGATIVE = 2;
/**
* Display a prompt with up to three buttons.
*
* @param view The GeckoView that triggered the prompt
* or null if the prompt is a global prompt.
* @param title Title for the prompt dialog.
* @param msg Message for the prompt dialog.
* @param btnMsg Array of 3 elements indicating labels for the individual buttons.
* btnMsg[BUTTON_TYPE_POSITIVE] is the label for the "positive" button.
* btnMsg[BUTTON_TYPE_NEUTRAL] is the label for the "neutral" button.
* btnMsg[BUTTON_TYPE_NEGATIVE] is the label for the "negative" button.
* The button is hidden if the corresponding label is null.
* @param callback Callback interface.
*/
void promptForButton(GeckoView view, String title, String msg,
String[] btnMsg, ButtonCallback callback);
/**
* Callback interface for notifying the result of prompts that have text results,
* including color and date/time pickers.
*/
interface TextCallback extends AlertCallback {
/**
* Called by the prompt implementation when the text prompt is confirmed by
* the user, for example by pressing the "OK" button.
*/
void confirm(String text);
}
/**
* Display a prompt for inputting text.
*
* @param view The GeckoView that triggered the prompt
* or null if the prompt is a global prompt.
* @param title Title for the prompt dialog.
* @param msg Message for the prompt dialog.
* @param value Default input text for the prompt.
* @param callback Callback interface.
*/
void promptForText(GeckoView view, String title, String msg,
String value, TextCallback callback);
/**
* Callback interface for notifying the result of authentication prompts.
*/
interface AuthCallback extends AlertCallback {
/**
* Called by the prompt implementation when a password-only prompt is
* confirmed by the user.
*/
void confirm(String password);
/**
* Called by the prompt implementation when a username/password prompt is
* confirmed by the user.
*/
void confirm(String username, String password);
}
/**
* The auth prompt is for a network host.
*/
static final int AUTH_FLAG_HOST = 1;
/**
* The auth prompt is for a proxy.
*/
static final int AUTH_FLAG_PROXY = 2;
/**
* The auth prompt should only request a password.
*/
static final int AUTH_FLAG_ONLY_PASSWORD = 8;
/**
* The auth prompt is the result of a previous failed login.
*/
static final int AUTH_FLAG_PREVIOUS_FAILED = 16;
/**
* The auth prompt is for a cross-origin sub-resource.
*/
static final int AUTH_FLAG_CROSS_ORIGIN_SUB_RESOURCE = 32;
/**
* The auth request is unencrypted or the encryption status is unknown.
*/
static final int AUTH_LEVEL_NONE = 0;
/**
* The auth request only encrypts password but not data.
*/
static final int AUTH_LEVEL_PW_ENCRYPTED = 1;
/**
* The auth request encrypts both password and data.
*/
static final int AUTH_LEVEL_SECURE = 2;
/**
* Display a prompt for authentication credentials.
*
* @param view The GeckoView that triggered the prompt
* or null if the prompt is a global prompt.
* @param title Title for the prompt dialog.
* @param msg Message for the prompt dialog.
* @param options Bundle containing options for the prompt with keys,
* "flags": int, bit field of AUTH_FLAG_* flags;
* "uri": String, URI for the auth request or null if unknown;
* "level": int, one of AUTH_LEVEL_* indicating level of encryption;
* "username": String, initial username or null if password-only;
* "password": String, intiial password;
* @param callback Callback interface.
*/
void promptForAuth(GeckoView view, String title, String msg,
GeckoBundle options, AuthCallback callback);
/**
* Callback interface for notifying the result of menu or list choice.
*/
interface ChoiceCallback extends AlertCallback {
/**
* Called by the prompt implementation when the menu or single-choice list is
* dismissed by the user.
*
* @param id ID of the selected item.
*/
void confirm(String id);
/**
* Called by the prompt implementation when the multiple-choice list is
* dismissed by the user.
*
* @param id IDs of the selected items.
*/
void confirm(String[] ids);
/**
* Called by the prompt implementation when the menu or single-choice list is
* dismissed by the user.
*
* @param item Bundle representing the selected item; must be an original
* GeckoBundle object that was passed to the implementation.
*/
void confirm(GeckoBundle item);
/**
* Called by the prompt implementation when the multiple-choice list is
* dismissed by the user.
*
* @param item Bundle array representing the selected items; must be original
* GeckoBundle objects that were passed to the implementation.
*/
void confirm(GeckoBundle[] items);
}
/**
* Display choices in a menu that dismisses as soon as an item is chosen.
*/
static final int CHOICE_TYPE_MENU = 1;
/**
* Display choices in a list that allows a single selection.
*/
static final int CHOICE_TYPE_SINGLE = 2;
/**
* Display choices in a list that allows multiple selections.
*/
static final int CHOICE_TYPE_MULTIPLE = 3;
/**
* Display a menu prompt or list prompt.
*
* @param view The GeckoView that triggered the prompt
* or null if the prompt is a global prompt.
* @param title Title for the prompt dialog, or null for no title.
* @param msg Message for the prompt dialog, or null for no message.
* @param type One of CHOICE_TYPE_* indicating the type of prompt.
* @param choices Array of bundles each representing an item or group, with keys,
* "disabled": boolean, true if the item should not be selectable;
* "icon": String, URI of the item icon or null if none
* (only valid for menus);
* "id": String, ID of the item or group;
* "items": GeckoBundle[], array of sub-items in a group or null
* if not a group.
* "label": String, label for displaying the item or group;
* "selected": boolean, true if the item should be pre-selected
* (pre-checked for menu items);
* "separator": boolean, true if the item should be a menu separator
* (only valid for menus);
* @param callback Callback interface.
*/
void promptForChoice(GeckoView view, String title, String msg, int type,
GeckoBundle[] choices, ChoiceCallback callback);
/**
* Display a color prompt.
*
* @param view The GeckoView that triggered the prompt
* or null if the prompt is a global prompt.
* @param title Title for the prompt dialog.
* @param value Initial color value in HTML color format.
* @param callback Callback interface; the result passed to confirm() must be in
* HTML color format.
*/
void promptForColor(GeckoView view, String title, String value,
TextCallback callback);
/**
* Prompt for year, month, and day.
*/
static final int DATETIME_TYPE_DATE = 1;
/**
* Prompt for year and month.
*/
static final int DATETIME_TYPE_MONTH = 2;
/**
* Prompt for year and week.
*/
static final int DATETIME_TYPE_WEEK = 3;
/**
* Prompt for hour and minute.
*/
static final int DATETIME_TYPE_TIME = 4;
/**
* Prompt for year, month, day, hour, and minute, without timezone.
*/
static final int DATETIME_TYPE_DATETIME_LOCAL = 5;
/**
* Display a date/time prompt.
*
* @param view The GeckoView that triggered the prompt
* or null if the prompt is a global prompt.
* @param title Title for the prompt dialog; currently always null.
* @param type One of DATETIME_TYPE_* indicating the type of prompt.
* @param value Initial date/time value in HTML date/time format.
* @param min Minimum date/time value in HTML date/time format.
* @param max Maximum date/time value in HTML date/time format.
* @param callback Callback interface; the result passed to confirm() must be in
* HTML date/time format.
*/
void promptForDateTime(GeckoView view, String title, int type,
String value, String min, String max, TextCallback callback);
/**
* Callback interface for notifying the result of file prompts.
*/
interface FileCallback extends AlertCallback {
/**
* Called by the prompt implementation when the user makes a file selection in
* single-selection mode.
*
* @param uri The URI of the selected file.
*/
void confirm(Uri uri);
/**
* Called by the prompt implementation when the user makes file selections in
* multiple-selection mode.
*
* @param uris Array of URI objects for the selected files.
*/
void confirm(Uri[] uris);
}
static final int FILE_TYPE_SINGLE = 1;
static final int FILE_TYPE_MULTIPLE = 2;
/**
* Display a file prompt.
*
* @param view The GeckoView that triggered the prompt
* or null if the prompt is a global prompt.
* @param title Title for the prompt dialog.
* @param type One of FILE_TYPE_* indicating the prompt type.
* @param mimeTypes Array of permissible MIME types for the selected files, in
* the form "type/subtype", where "type" and/or "subtype" can be
* "*" to indicate any value.
* @param callback Callback interface.
*/
void promptForFile(GeckoView view, String title, int type,
String[] mimeTypes, FileCallback callback);
}
}

View File

@ -1,58 +0,0 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko;
import android.os.Bundle;
public class GeckoViewChrome implements GeckoView.ChromeDelegate {
/**
* Tell the host application to display an alert dialog.
* @param view The GeckoView that initiated the callback.
* @param message The string to display in the dialog.
* @param result A PromptResult used to send back the result without blocking.
* Defaults to cancel requests.
*/
@Override
public void onAlert(GeckoView view, String message, GeckoView.PromptResult result) {
result.cancel();
}
/**
* Tell the host application to display a confirmation dialog.
* @param view The GeckoView that initiated the callback.
* @param message The string to display in the dialog.
* @param result A PromptResult used to send back the result without blocking.
* Defaults to cancel requests.
*/
@Override
public void onConfirm(GeckoView view, String message, GeckoView.PromptResult result) {
result.cancel();
}
/**
* Tell the host application to display an input prompt dialog.
* @param view The GeckoView that initiated the callback.
* @param message The string to display in the dialog.
* @param defaultValue The string to use as default input.
* @param result A PromptResult used to send back the result without blocking.
* Defaults to cancel requests.
*/
@Override
public void onPrompt(GeckoView view, String message, String defaultValue, GeckoView.PromptResult result) {
result.cancel();
}
/**
* Tell the host application to display a remote debugging request dialog.
* @param view The GeckoView that initiated the callback.
* @param result A PromptResult used to send back the result without blocking.
* Defaults to cancel requests.
*/
@Override
public void onDebugRequest(GeckoView view, GeckoView.PromptResult result) {
result.cancel();
}
}

View File

@ -0,0 +1,783 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.geckoview_example;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.net.Uri;
import android.os.Build;
import android.text.InputType;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.InflateException;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CheckedTextView;
import android.widget.CompoundButton;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.TimePicker;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import org.mozilla.gecko.GeckoView;
import org.mozilla.gecko.util.GeckoBundle;
final class BasicGeckoViewPrompt implements GeckoView.PromptDelegate {
protected static final String LOGTAG = "BasicGeckoViewPrompt";
public int filePickerRequestCode = 1;
private int mFileType;
private FileCallback mFileCallback;
private static Activity getActivity(final GeckoView view) {
if (view != null) {
final Context context = view.getContext();
if (context instanceof Activity) {
return (Activity) context;
}
}
return null;
}
private AlertDialog.Builder addCheckbox(final AlertDialog.Builder builder,
ViewGroup parent,
final AlertCallback callback) {
if (!callback.hasCheckbox()) {
return builder;
}
final CheckBox checkbox = new CheckBox(builder.getContext());
if (callback.getCheckboxMessage() != null) {
checkbox.setText(callback.getCheckboxMessage());
}
checkbox.setChecked(callback.getCheckboxValue());
checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(final CompoundButton button,
final boolean checked) {
callback.setCheckboxValue(checked);
}
});
if (parent == null) {
final int padding = getViewPadding(builder);
parent = new FrameLayout(builder.getContext());
parent.setPadding(/* left */ padding, /* top */ 0,
/* right */ padding, /* bottom */ 0);
builder.setView(parent);
}
parent.addView(checkbox);
return builder;
}
public void alert(final GeckoView view, final String title, final String msg,
final AlertCallback callback) {
final Activity activity = getActivity(view);
if (activity == null) {
callback.dismiss();
return;
}
final AlertDialog.Builder builder = new AlertDialog.Builder(activity)
.setTitle(title)
.setMessage(msg)
.setPositiveButton(android.R.string.ok, /* onClickListener */ null)
.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(final DialogInterface dialog) {
callback.dismiss();
}
});
addCheckbox(builder, /* parent */ null, callback).show();
}
public void promptForButton(final GeckoView view, final String title, final String msg,
final String[] btnMsg, final ButtonCallback callback)
{
final Activity activity = getActivity(view);
if (activity == null) {
callback.dismiss();
return;
}
final AlertDialog.Builder builder = new AlertDialog.Builder(activity)
.setTitle(title)
.setMessage(msg)
.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(final DialogInterface dialog) {
callback.dismiss();
}
});
final DialogInterface.OnClickListener listener =
new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
callback.confirm(BUTTON_TYPE_POSITIVE);
} else if (which == DialogInterface.BUTTON_NEUTRAL) {
callback.confirm(BUTTON_TYPE_NEUTRAL);
} else if (which == DialogInterface.BUTTON_NEGATIVE) {
callback.confirm(BUTTON_TYPE_NEGATIVE);
} else {
callback.dismiss();
}
}
};
if (btnMsg[BUTTON_TYPE_POSITIVE] != null) {
builder.setPositiveButton(btnMsg[BUTTON_TYPE_POSITIVE], listener);
}
if (btnMsg[BUTTON_TYPE_NEUTRAL] != null) {
builder.setNeutralButton(btnMsg[BUTTON_TYPE_NEUTRAL], listener);
}
if (btnMsg[BUTTON_TYPE_NEGATIVE] != null) {
builder.setNegativeButton(btnMsg[BUTTON_TYPE_NEGATIVE], listener);
}
addCheckbox(builder, /* parent */ null, callback).show();
}
private int getViewPadding(final AlertDialog.Builder builder) {
final TypedArray attr = builder.getContext().obtainStyledAttributes(
new int[] { android.R.attr.listPreferredItemPaddingLeft });
return attr.getDimensionPixelSize(0, 1);
}
private LinearLayout addStandardLayout(final AlertDialog.Builder builder,
final String title, final String msg,
final AlertCallback callback) {
final ScrollView scrollView = new ScrollView(builder.getContext());
final LinearLayout container = new LinearLayout(builder.getContext());
final int padding = getViewPadding(builder);
container.setOrientation(LinearLayout.VERTICAL);
container.setPadding(/* left */ padding, /* top */ 0,
/* right */ padding, /* bottom */ 0);
scrollView.addView(container);
builder.setTitle(title)
.setMessage(msg)
.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(final DialogInterface dialog) {
callback.dismiss();
}
})
.setView(scrollView);
return container;
}
public void promptForText(final GeckoView view, final String title, final String msg,
final String value, final TextCallback callback)
{
final Activity activity = getActivity(view);
if (activity == null) {
callback.dismiss();
return;
}
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
final LinearLayout container = addStandardLayout(builder, title, msg, callback);
final EditText editText = new EditText(builder.getContext());
editText.setText(value);
container.addView(editText);
builder.setNegativeButton(android.R.string.cancel, /* listener */ null)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int which) {
callback.confirm(editText.getText().toString());
}
});
addCheckbox(builder, container, callback).show();
}
public void promptForAuth(final GeckoView view, final String title, final String msg,
final GeckoBundle options, final AuthCallback callback)
{
final Activity activity = getActivity(view);
if (activity == null) {
callback.dismiss();
return;
}
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
final LinearLayout container = addStandardLayout(builder, title, msg, callback);
final int flags = options.getInt("flags");
final int level = options.getInt("level");
final EditText username;
if ((flags & AUTH_FLAG_ONLY_PASSWORD) == 0) {
username = new EditText(builder.getContext());
username.setHint(R.string.username);
username.setText(options.getString("username"));
container.addView(username);
} else {
username = null;
}
final EditText password = new EditText(builder.getContext());
password.setHint(R.string.password);
password.setText(options.getString("password"));
password.setInputType(InputType.TYPE_CLASS_TEXT |
InputType.TYPE_TEXT_VARIATION_PASSWORD);
container.addView(password);
if (level != AUTH_LEVEL_NONE) {
final ImageView secure = new ImageView(builder.getContext());
secure.setImageResource(android.R.drawable.ic_lock_lock);
container.addView(secure);
}
builder.setNegativeButton(android.R.string.cancel, /* listener */ null)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int which) {
if ((flags & AUTH_FLAG_ONLY_PASSWORD) == 0) {
callback.confirm(username.getText().toString(),
password.getText().toString());
} else {
callback.confirm(password.getText().toString());
}
}
});
addCheckbox(builder, container, callback).show();
}
private void addChoiceItems(final int type, final ArrayAdapter<GeckoBundle> list,
final GeckoBundle[] items, final String indent) {
if (type == CHOICE_TYPE_MENU) {
list.addAll(items);
return;
}
for (final GeckoBundle item : items) {
final GeckoBundle[] children = item.getBundleArray("items");
if (indent != null && children == null) {
item.putString("label", indent + item.getString("label", ""));
}
list.add(item);
if (children != null) {
final String newIndent;
if (type == CHOICE_TYPE_SINGLE || type == CHOICE_TYPE_MULTIPLE) {
newIndent = (indent != null) ? indent + '\t' : "\t";
} else {
newIndent = null;
}
addChoiceItems(type, list, children, newIndent);
}
}
}
public void promptForChoice(final GeckoView view, final String title, final String msg,
final int type, final GeckoBundle[] choices,
final ChoiceCallback callback)
{
final Activity activity = getActivity(view);
if (activity == null) {
callback.dismiss();
return;
}
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
addStandardLayout(builder, title, msg, callback);
final ArrayAdapter<GeckoBundle> adapter = new ArrayAdapter<GeckoBundle>(
builder.getContext(), android.R.layout.simple_list_item_1) {
private static final int TYPE_MENU_ITEM = 0;
private static final int TYPE_MENU_CHECK = 1;
private static final int TYPE_SEPARATOR = 2;
private static final int TYPE_GROUP = 3;
private static final int TYPE_SINGLE = 4;
private static final int TYPE_MULTIPLE = 5;
private static final int TYPE_COUNT = 6;
private LayoutInflater mInflater;
private View mSeparator;
@Override
public int getViewTypeCount() {
return TYPE_COUNT;
}
@Override
public int getItemViewType(final int position) {
final GeckoBundle item = getItem(position);
if (item.getBoolean("separator")) {
return TYPE_SEPARATOR;
} else if (type == CHOICE_TYPE_MENU) {
return item.getBoolean("selected") ? TYPE_MENU_CHECK : TYPE_MENU_ITEM;
} else if (item.containsKey("items")) {
return TYPE_GROUP;
} else if (type == CHOICE_TYPE_SINGLE) {
return TYPE_SINGLE;
} else if (type == CHOICE_TYPE_MULTIPLE) {
return TYPE_MULTIPLE;
} else {
throw new UnsupportedOperationException();
}
}
@Override
public boolean isEnabled(final int position) {
final GeckoBundle item = getItem(position);
return !item.getBoolean("separator") && !item.getBoolean("disabled") &&
((type != CHOICE_TYPE_SINGLE && type != CHOICE_TYPE_MULTIPLE) ||
!item.containsKey("items"));
}
@Override
public View getView(final int position, View view,
final ViewGroup parent) {
final int itemType = getItemViewType(position);
final int layoutId;
if (itemType == TYPE_SEPARATOR) {
if (mSeparator == null) {
mSeparator = new View(getContext());
mSeparator.setLayoutParams(new ListView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, 2, itemType));
final TypedArray attr = getContext().obtainStyledAttributes(
new int[] { android.R.attr.listDivider });
mSeparator.setBackgroundResource(attr.getResourceId(0, 0));
attr.recycle();
}
return mSeparator;
} else if (itemType == TYPE_MENU_ITEM) {
layoutId = android.R.layout.simple_list_item_1;
} else if (itemType == TYPE_MENU_CHECK) {
layoutId = android.R.layout.simple_list_item_checked;
} else if (itemType == TYPE_GROUP) {
layoutId = android.R.layout.preference_category;
} else if (itemType == TYPE_SINGLE) {
layoutId = android.R.layout.simple_list_item_single_choice;
} else if (itemType == TYPE_MULTIPLE) {
layoutId = android.R.layout.simple_list_item_multiple_choice;
} else {
throw new UnsupportedOperationException();
}
if (view == null) {
if (mInflater == null) {
mInflater = LayoutInflater.from(builder.getContext());
}
view = mInflater.inflate(layoutId, parent, false);
}
final GeckoBundle item = getItem(position);
final TextView text = (TextView) view;
text.setEnabled(!item.getBoolean("disabled"));
text.setText(item.getString("label"));
if (view instanceof CheckedTextView) {
((CheckedTextView) view).setChecked(item.getBoolean("selected"));
}
return view;
}
};
addChoiceItems(type, adapter, choices, /* indent */ null);
final ListView list = new ListView(builder.getContext());
list.setAdapter(adapter);
if (type == CHOICE_TYPE_MULTIPLE) {
list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
}
builder.setView(list);
final AlertDialog dialog = builder.create();
if (type == CHOICE_TYPE_SINGLE || type == CHOICE_TYPE_MENU) {
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(final AdapterView<?> parent, final View v,
final int position, final long id) {
final GeckoBundle item = adapter.getItem(position);
if (type == CHOICE_TYPE_MENU) {
final GeckoBundle[] children = item.getBundleArray("items");
if (children != null) {
// Show sub-menu.
dialog.setOnDismissListener(null);
dialog.dismiss();
promptForChoice(view, item.getString("label"), /* msg */ null,
type, children, callback);
return;
}
}
callback.confirm(item);
dialog.dismiss();
}
});
} else if (type == CHOICE_TYPE_MULTIPLE) {
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(final AdapterView<?> parent, final View v,
final int position, final long id) {
final GeckoBundle item = adapter.getItem(position);
item.putBoolean("selected", ((CheckedTextView) v).isChecked());
}
});
builder.setNegativeButton(android.R.string.cancel, /* listener */ null)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog,
final int which) {
final int len = adapter.getCount();
ArrayList<String> items = new ArrayList<>(len);
for (int i = 0; i < len; i++) {
final GeckoBundle item = adapter.getItem(i);
if (item.getBoolean("selected")) {
items.add(item.getString("id"));
}
}
callback.confirm(items.toArray(new GeckoBundle[items.size()]));
}
});
} else {
throw new UnsupportedOperationException();
}
dialog.show();
}
private static int parseColor(final String value, final int def) {
try {
return Color.parseColor(value);
} catch (final IllegalArgumentException e) {
return def;
}
}
public void promptForColor(final GeckoView view, final String title,
final String value, final TextCallback callback)
{
final Activity activity = getActivity(view);
if (activity == null) {
callback.dismiss();
return;
}
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
addStandardLayout(builder, title, /* msg */ null, callback);
final int initial = parseColor(value, /* def */ 0);
final ArrayAdapter<Integer> adapter = new ArrayAdapter<Integer>(
builder.getContext(), android.R.layout.simple_list_item_1) {
private LayoutInflater mInflater;
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public int getItemViewType(final int position) {
return (getItem(position) == initial) ? 1 : 0;
}
@Override
public View getView(final int position, View view,
final ViewGroup parent) {
if (mInflater == null) {
mInflater = LayoutInflater.from(builder.getContext());
}
final int color = getItem(position);
if (view == null) {
view = mInflater.inflate((color == initial) ?
android.R.layout.simple_list_item_checked :
android.R.layout.simple_list_item_1, parent, false);
}
view.setBackgroundResource(android.R.drawable.editbox_background);
view.getBackground().setColorFilter(color, PorterDuff.Mode.MULTIPLY);
return view;
}
};
adapter.addAll(0xffff4444 /* holo_red_light */,
0xffcc0000 /* holo_red_dark */,
0xffffbb33 /* holo_orange_light */,
0xffff8800 /* holo_orange_dark */,
0xff99cc00 /* holo_green_light */,
0xff669900 /* holo_green_dark */,
0xff33b5e5 /* holo_blue_light */,
0xff0099cc /* holo_blue_dark */,
0xffaa66cc /* holo_purple */,
0xffffffff /* white */,
0xffaaaaaa /* lighter_gray */,
0xff555555 /* darker_gray */,
0xff000000 /* black */);
final ListView list = new ListView(builder.getContext());
list.setAdapter(adapter);
builder.setView(list);
final AlertDialog dialog = builder.create();
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(final AdapterView<?> parent, final View v,
final int position, final long id) {
callback.confirm(String.format("#%06x", 0xffffff & adapter.getItem(position)));
dialog.dismiss();
}
});
dialog.show();
}
private static Date parseDate(final SimpleDateFormat formatter,
final String value,
final boolean defaultToNow) {
try {
if (value != null && !value.isEmpty()) {
return formatter.parse(value);
}
} catch (final ParseException e) {
}
return defaultToNow ? new Date() : null;
}
@SuppressWarnings("deprecation")
private static void setTimePickerTime(final TimePicker picker, final Calendar cal) {
if (Build.VERSION.SDK_INT >= 23) {
picker.setHour(cal.get(Calendar.HOUR_OF_DAY));
picker.setMinute(cal.get(Calendar.MINUTE));
} else {
picker.setCurrentHour(cal.get(Calendar.HOUR_OF_DAY));
picker.setCurrentMinute(cal.get(Calendar.MINUTE));
}
}
@SuppressWarnings("deprecation")
private static void setCalendarTime(final Calendar cal, final TimePicker picker) {
if (Build.VERSION.SDK_INT >= 23) {
cal.set(Calendar.HOUR_OF_DAY, picker.getHour());
cal.set(Calendar.MINUTE, picker.getMinute());
} else {
cal.set(Calendar.HOUR_OF_DAY, picker.getCurrentHour());
cal.set(Calendar.MINUTE, picker.getCurrentMinute());
}
}
public void promptForDateTime(final GeckoView view, final String title, final int type,
final String value, final String min, final String max,
final TextCallback callback)
{
final Activity activity = getActivity(view);
if (activity == null) {
callback.dismiss();
return;
}
final String format;
if (type == DATETIME_TYPE_DATE) {
format = "yyyy-MM-dd";
} else if (type == DATETIME_TYPE_MONTH) {
format = "yyyy-MM";
} else if (type == DATETIME_TYPE_WEEK) {
format = "yyyy-'W'ww";
} else if (type == DATETIME_TYPE_TIME) {
format = "HH:mm";
} else if (type == DATETIME_TYPE_DATETIME_LOCAL) {
format = "yyyy-MM-dd'T'HH:mm";
} else {
throw new UnsupportedOperationException();
}
final SimpleDateFormat formatter = new SimpleDateFormat(format, Locale.ROOT);
final Date minDate = parseDate(formatter, min, /* defaultToNow */ false);
final Date maxDate = parseDate(formatter, max, /* defaultToNow */ false);
final Date date = parseDate(formatter, value, /* defaultToNow */ true);
final Calendar cal = formatter.getCalendar();
cal.setTime(date);
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
final LayoutInflater inflater = LayoutInflater.from(builder.getContext());
final DatePicker datePicker;
if (type == DATETIME_TYPE_DATE || type == DATETIME_TYPE_MONTH ||
type == DATETIME_TYPE_WEEK || type == DATETIME_TYPE_DATETIME_LOCAL) {
final int resId = builder.getContext().getResources().getIdentifier(
"date_picker_dialog", "layout", "android");
DatePicker picker = null;
if (resId != 0) {
try {
picker = (DatePicker) inflater.inflate(resId, /* root */ null);
} catch (final ClassCastException|InflateException e) {
}
}
if (picker == null) {
picker = new DatePicker(builder.getContext());
}
picker.init(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
cal.get(Calendar.DAY_OF_MONTH), /* listener */ null);
if (minDate != null) {
picker.setMinDate(minDate.getTime());
}
if (maxDate != null) {
picker.setMaxDate(maxDate.getTime());
}
datePicker = picker;
} else {
datePicker = null;
}
final TimePicker timePicker;
if (type == DATETIME_TYPE_TIME || type == DATETIME_TYPE_DATETIME_LOCAL) {
final int resId = builder.getContext().getResources().getIdentifier(
"time_picker_dialog", "layout", "android");
TimePicker picker = null;
if (resId != 0) {
try {
picker = (TimePicker) inflater.inflate(resId, /* root */ null);
} catch (final ClassCastException|InflateException e) {
}
}
if (picker == null) {
picker = new TimePicker(builder.getContext());
}
setTimePickerTime(picker, cal);
picker.setIs24HourView(DateFormat.is24HourFormat(builder.getContext()));
timePicker = picker;
} else {
timePicker = null;
}
final LinearLayout container = addStandardLayout(builder, title,
/* msg */ null, callback);
container.setPadding(/* left */ 0, /* top */ 0, /* right */ 0, /* bottom */ 0);
if (datePicker != null) {
container.addView(datePicker);
}
if (timePicker != null) {
container.addView(timePicker);
}
final DialogInterface.OnClickListener listener =
new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int which) {
if (which == DialogInterface.BUTTON_NEUTRAL) {
// Clear
callback.confirm("");
return;
}
if (datePicker != null) {
cal.set(datePicker.getYear(), datePicker.getMonth(),
datePicker.getDayOfMonth());
}
if (timePicker != null) {
setCalendarTime(cal, timePicker);
}
callback.confirm(formatter.format(cal.getTime()));
}
};
builder.setNegativeButton(android.R.string.cancel, /* listener */ null)
.setNeutralButton(R.string.clear_field, listener)
.setPositiveButton(android.R.string.ok, listener)
.show();
}
public void promptForFile(GeckoView view, String title, int type,
String[] mimeTypes, FileCallback callback)
{
final Activity activity = getActivity(view);
if (activity == null) {
callback.dismiss();
return;
}
// Merge all given MIME types into one, using wildcard if needed.
String mimeType = null;
String mimeSubtype = null;
for (final String rawType : mimeTypes) {
final String normalizedType = rawType.trim().toLowerCase(Locale.ROOT);
final int len = normalizedType.length();
int slash = normalizedType.indexOf('/');
if (slash < 0) {
slash = len;
}
final String newType = normalizedType.substring(0, slash);
final String newSubtype = normalizedType.substring(Math.min(slash + 1, len));
if (mimeType == null) {
mimeType = newType;
} else if (!mimeType.equals(newType)) {
mimeType = "*";
}
if (mimeSubtype == null) {
mimeSubtype = newSubtype;
} else if (!mimeSubtype.equals(newSubtype)) {
mimeSubtype = "*";
}
}
final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType((mimeType != null ? mimeType : "*") + '/' +
(mimeSubtype != null ? mimeSubtype : "*"));
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
if (type == FILE_TYPE_MULTIPLE) {
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
}
if (mimeTypes.length > 0) {
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
}
try {
mFileType = type;
mFileCallback = callback;
activity.startActivityForResult(intent, filePickerRequestCode);
} catch (final ActivityNotFoundException e) {
Log.e(LOGTAG, "Cannot launch activity", e);
callback.dismiss();
}
}
public void onFileCallbackResult(final int resultCode, final Intent data) {
if (mFileCallback == null) {
return;
}
final FileCallback callback = mFileCallback;
mFileCallback = null;
if (resultCode != Activity.RESULT_OK || data == null) {
callback.dismiss();
return;
}
final Uri uri = data.getData();
final ClipData clip = data.getClipData();
if (mFileType == FILE_TYPE_SINGLE ||
(mFileType == FILE_TYPE_MULTIPLE && clip == null)) {
callback.confirm(uri);
} else if (mFileType == FILE_TYPE_MULTIPLE) {
if (clip == null) {
Log.w(LOGTAG, "No selected file");
callback.dismiss();
return;
}
final int count = clip.getItemCount();
final ArrayList<Uri> uris = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
uris.add(clip.getItemAt(i).getUri());
}
callback.confirm(uris.toArray(new Uri[uris.size()]));
}
}
}

View File

@ -6,13 +6,10 @@
package org.mozilla.geckoview_example;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import org.mozilla.gecko.BaseGeckoInterface;
import org.mozilla.gecko.GeckoProfile;
@ -25,7 +22,9 @@ public class GeckoViewActivity extends Activity {
private static final String LOGTAG = "GeckoViewActivity";
private static final String DEFAULT_URL = "https://mozilla.org";
GeckoView mGeckoView;
/* package */ static final int REQUEST_FILE_PICKER = 1;
private GeckoView mGeckoView;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -36,10 +35,13 @@ public class GeckoViewActivity extends Activity {
setContentView(R.layout.geckoview_activity);
mGeckoView = (GeckoView) findViewById(R.id.gecko_view);
mGeckoView.setChromeDelegate(new MyGeckoViewChrome());
mGeckoView.setContentListener(new MyGeckoViewContent());
mGeckoView.setProgressListener(new MyGeckoViewProgress());
final BasicGeckoViewPrompt prompt = new BasicGeckoViewPrompt();
prompt.filePickerRequestCode = REQUEST_FILE_PICKER;
mGeckoView.setPromptDelegate(prompt);
final GeckoProfile profile = GeckoProfile.get(this);
GeckoThread.initMainProcess(profile, /* args */ null, /* debugging */ false);
@ -63,45 +65,15 @@ public class GeckoViewActivity extends Activity {
}
}
private class MyGeckoViewChrome implements GeckoView.ChromeDelegate {
@Override
public void onAlert(GeckoView view, String message, GeckoView.PromptResult result) {
Log.i(LOGTAG, "Alert!");
result.confirm();
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
}
@Override
public void onConfirm(GeckoView view, String message, final GeckoView.PromptResult result) {
Log.i(LOGTAG, "Confirm!");
new AlertDialog.Builder(GeckoViewActivity.this)
.setTitle("javaScript dialog")
.setMessage(message)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
})
.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
})
.create()
.show();
}
@Override
public void onPrompt(GeckoView view, String message, String defaultValue, GeckoView.PromptResult result) {
result.cancel();
}
@Override
public void onDebugRequest(GeckoView view, GeckoView.PromptResult result) {
Log.i(LOGTAG, "Remote Debug!");
result.confirm();
@Override
protected void onActivityResult(final int requestCode, final int resultCode,
final Intent data) {
if (requestCode == REQUEST_FILE_PICKER) {
final BasicGeckoViewPrompt prompt = (BasicGeckoViewPrompt)
mGeckoView.getPromptDelegate();
prompt.onFileCallbackResult(resultCode, data);
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}

View File

@ -1,3 +1,6 @@
<resources>
<string name="app_name">geckoview_example</string>
<string name="username">Username</string>
<string name="password">Password</string>
<string name="clear_field">Clear</string>
</resources>

View File

@ -531,7 +531,10 @@
@BINPATH@/chrome/geckoview@JAREXT@
@BINPATH@/chrome/geckoview.manifest
#ifndef MOZ_GECKOVIEW_JAR
#ifdef MOZ_GECKOVIEW_JAR
@BINPATH@/components/GeckoView.manifest
@BINPATH@/components/GeckoViewPrompt.js
#else
@BINPATH@/chrome/chrome@JAREXT@
@BINPATH@/chrome/chrome.manifest
@BINPATH@/components/AboutRedirector.js

View File

@ -315,6 +315,17 @@ interface nsIPermissionManager : nsISupports
* @param perms An array with the permissions which match the given key.
*/
void setPermissionsWithKey(in ACString permissionKey, in IPCPermissionArrayRef perms);
/**
* Broadcasts permissions for the given principal to all content processes.
*
* DO NOT USE THIS METHOD if you can avoid it. It was added in bug XXX to
* handle the current temporary implementation of ServiceWorker debugging. It
* will be removed when service worker debugging is fixed.
*
* @param aPrincipal The principal to broadcast permissions for.
*/
void broadcastPermissionsForPrincipalToAllContentProcesses(in nsIPrincipal aPrincipal);
};
%{ C++

View File

@ -5,12 +5,14 @@
<script src=/resources/testharnessreport.js></script>
<div id="log"></div>
<script>
let option = {timeout: 50};
async_test(function (t) {
assert_false(document.hidden, "document.hidden must exist and be false to run this test properly");
var counter = 0;
function f(c) {
assert_equals(counter, c);
if (counter === 99) {
if (counter === 49) {
t.done();
}
@ -18,7 +20,7 @@
}
for (var i = 0; i < 100; ++i) {
let j = i;
window.requestIdleCallback(t.step_func(function () { f(j) }));
window.requestIdleCallback(t.step_func(function () { f(j) }), option);
}
}, "requestIdleCallback callbacks should be invoked in order (called iteratively)");
@ -28,14 +30,17 @@
function f(c) {
assert_equals(counter, c);
if (counter === 99) {
if (counter === 49) {
t.done();
}
++counter;
window.requestIdleCallback(t.step_func(function () { f(c + 1) }));
window.requestIdleCallback(t.step_func(function () { f(c + 1) }), option);
}
window.requestIdleCallback(t.step_func(function () { f(0) }));
window.requestIdleCallback(t.step_func(function () { f(0) }), option);
}, "requestIdleCallback callbacks should be invoked in order (called recursively)");
let generateIdlePeriods = _ => requestAnimationFrame(generateIdlePeriods);
generateIdlePeriods();
</script>

View File

@ -580,21 +580,29 @@ nsAppShell::Observe(nsISupports* aSubject,
removeObserver = true;
} else if (!strcmp(aTopic, "chrome-document-loaded")) {
if (jni::IsAvailable()) {
// Our first window has loaded, assume any JS initialization has run.
java::GeckoThread::CheckAndSetState(
java::GeckoThread::State::PROFILE_READY(),
java::GeckoThread::State::RUNNING());
}
// Enable the window event dispatcher for the given GeckoView.
// Set the global ready state and enable the window event dispatcher
// for this particular GeckoView.
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aSubject);
MOZ_ASSERT(doc);
nsCOMPtr<nsIWidget> widget =
WidgetUtils::DOMWindowToWidget(doc->GetWindow());
MOZ_ASSERT(widget);
if (widget->WindowType() == nsWindowType::eWindowType_toplevel) {
// Make sure to call this only on top level nsWindow.
// `widget` may be one of several different types in the parent
// process, including the Android nsWindow, PuppetWidget, etc. To
// ensure that we only accept the Android nsWindow, we check that the
// widget is a top-level window and that its NS_NATIVE_WIDGET value is
// non-null, which is not the case for non-native widgets like
// PuppetWidget.
if (widget &&
widget->WindowType() == nsWindowType::eWindowType_toplevel &&
widget->GetNativeData(NS_NATIVE_WIDGET) == widget) {
if (jni::IsAvailable()) {
// When our first window has loaded, assume any JS
// initialization has run and set Gecko to ready.
java::GeckoThread::CheckAndSetState(
java::GeckoThread::State::PROFILE_READY(),
java::GeckoThread::State::RUNNING());
}
const auto window = static_cast<nsWindow*>(widget.get());
window->EnableEventDispatcher();
}