mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Merge mozilla-central to autoland
This commit is contained in:
commit
7bcdfe36bc
@ -6248,7 +6248,7 @@
|
||||
if (width != this.mTabstripWidth) {
|
||||
this.adjustTabstrip();
|
||||
this._fillTrailingGap();
|
||||
this._handleTabSelect();
|
||||
this._handleTabSelect(false);
|
||||
this.mTabstripWidth = width;
|
||||
}
|
||||
break;
|
||||
|
@ -11,4 +11,4 @@ BROWSER_CHROME_MANIFESTS += [
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('Firefox', 'Contextual Identity')
|
||||
BUG_COMPONENT = ('DOM', 'Security')
|
||||
|
@ -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]
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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(
|
||||
{
|
||||
|
@ -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(
|
||||
|
@ -118,9 +118,7 @@ module.exports = createClass({
|
||||
let { nodeFront } = grid;
|
||||
|
||||
return dom.li(
|
||||
{
|
||||
className: "grid-item",
|
||||
},
|
||||
{},
|
||||
dom.label(
|
||||
{},
|
||||
dom.input(
|
||||
|
@ -52,6 +52,7 @@ const App = createClass({
|
||||
return dom.div(
|
||||
{
|
||||
id: "layout-container",
|
||||
className: "devtools-monospace",
|
||||
},
|
||||
Accordion({
|
||||
items: [
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
});
|
||||
|
@ -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
|
||||
|
@ -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) it’s 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;
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
162
dom/bindings/parser/tests/test_cereactions.py
Normal file
162
dom/bindings/parser/tests/test_cereactions.py
Normal 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")
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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";
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
}
|
||||
|
25
js/src/jit-test/tests/ion/math-max-arraylength.js
Normal file
25
js/src/jit-test/tests/ion/math-max-arraylength.js
Normal 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();
|
13
js/src/jit-test/tests/self-hosting/tolength.js
Normal file
13
js/src/jit-test/tests/self-hosting/tolength.js
Normal 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);
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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)) {
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
/**
|
||||
|
34
layout/reftests/css-grid/bug1349571-ref.html
Normal file
34
layout/reftests/css-grid/bug1349571-ref.html
Normal 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>
|
38
layout/reftests/css-grid/bug1349571.html
Normal file
38
layout/reftests/css-grid/bug1349571.html
Normal 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>
|
32
layout/reftests/css-grid/bug1350925-ref.html
Normal file
32
layout/reftests/css-grid/bug1350925-ref.html
Normal 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>
|
32
layout/reftests/css-grid/bug1350925.html
Normal file
32
layout/reftests/css-grid/bug1350925.html
Normal 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>
|
25
layout/reftests/css-grid/bug1356820-ref.html
Normal file
25
layout/reftests/css-grid/bug1356820-ref.html
Normal 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>
|
25
layout/reftests/css-grid/bug1356820.html
Normal file
25
layout/reftests/css-grid/bug1356820.html
Normal 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>
|
@ -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>
|
74
layout/reftests/css-grid/grid-item-overflow-stretch-001.html
Normal file
74
layout/reftests/css-grid/grid-item-overflow-stretch-001.html
Normal 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>
|
@ -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>
|
75
layout/reftests/css-grid/grid-item-overflow-stretch-002.html
Normal file
75
layout/reftests/css-grid/grid-item-overflow-stretch-002.html
Normal 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>
|
@ -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>
|
75
layout/reftests/css-grid/grid-item-overflow-stretch-003.html
Normal file
75
layout/reftests/css-grid/grid-item-overflow-stretch-003.html
Normal 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>
|
@ -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>
|
82
layout/reftests/css-grid/grid-item-overflow-stretch-004.html
Normal file
82
layout/reftests/css-grid/grid-item-overflow-stretch-004.html
Normal 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>
|
@ -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>
|
77
layout/reftests/css-grid/grid-item-overflow-stretch-005.html
Normal file
77
layout/reftests/css-grid/grid-item-overflow-stretch-005.html
Normal 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>
|
@ -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>
|
56
layout/reftests/css-grid/grid-item-overflow-stretch-006.html
Normal file
56
layout/reftests/css-grid/grid-item-overflow-stretch-006.html
Normal 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>
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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',
|
||||
|
10
mobile/android/components/geckoview/GeckoView.manifest
Normal file
10
mobile/android/components/geckoview/GeckoView.manifest
Normal 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
|
1062
mobile/android/components/geckoview/GeckoViewPrompt.js
Normal file
1062
mobile/android/components/geckoview/GeckoViewPrompt.js
Normal file
File diff suppressed because it is too large
Load Diff
10
mobile/android/components/geckoview/moz.build
Normal file
10
mobile/android/components/geckoview/moz.build
Normal 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',
|
||||
]
|
@ -50,4 +50,5 @@ EXTRA_PP_COMPONENTS += [
|
||||
DIRS += [
|
||||
'extensions',
|
||||
'build',
|
||||
'geckoview',
|
||||
]
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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()]));
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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++
|
||||
|
@ -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>
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user