Merge autoland to m-c, a=merge

MozReview-Commit-ID: HAS6ji3eShV
This commit is contained in:
Phil Ringnalda 2016-12-27 20:31:38 -08:00
Родитель 14daa764d4 328e848980
Коммит d376a758dc
82 изменённых файлов: 533 добавлений и 550 удалений

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

@ -57,6 +57,11 @@ var gAdvancedPane = {
if (Services.prefs.getBoolPref("browser.storageManager.enabled")) {
Services.obs.addObserver(this, "sitedatamanager:sites-updated", false);
let unload = () => {
window.removeEventListener("unload", unload);
Services.obs.removeObserver(this, "sitedatamanager:sites-updated");
};
window.addEventListener("unload", unload);
SiteDataManager.updateSites();
setEventListener("clearSiteDataButton", "command",
gAdvancedPane.clearSiteData);

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

@ -8,8 +8,10 @@
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr, manager: Cm} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
let {FormAutoCompleteResult} = Cu.import("resource://gre/modules/nsFormAutoCompleteResult.jsm", {});
/**
* Handles profile autofill for a DOM Form element.
@ -131,3 +133,110 @@ FormAutofillHandler.prototype = {
}
},
};
// Register/unregister a constructor as a factory.
function AutocompleteFactory() {}
AutocompleteFactory.prototype = {
register(targetConstructor) {
let proto = targetConstructor.prototype;
this._classID = proto.classID;
let factory = XPCOMUtils._getFactory(targetConstructor);
this._factory = factory;
let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
registrar.registerFactory(proto.classID, proto.classDescription,
proto.contractID, factory);
if (proto.classID2) {
this._classID2 = proto.classID2;
registrar.registerFactory(proto.classID2, proto.classDescription,
proto.contractID2, factory);
}
},
unregister() {
let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
registrar.unregisterFactory(this._classID, this._factory);
if (this._classID2) {
registrar.unregisterFactory(this._classID2, this._factory);
}
this._factory = null;
},
};
/**
* @constructor
*
* @implements {nsIAutoCompleteSearch}
*/
function AutofillProfileAutoCompleteSearch() {
}
AutofillProfileAutoCompleteSearch.prototype = {
classID: Components.ID("4f9f1e4c-7f2c-439e-9c9e-566b68bc187d"),
contractID: "@mozilla.org/autocomplete/search;1?name=autofill-profiles",
classDescription: "AutofillProfileAutoCompleteSearch",
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteSearch]),
// Begin nsIAutoCompleteSearch implementation
/**
* Searches for a given string and notifies a listener (either synchronously
* or asynchronously) of the result
*
* @param {string} searchString the string to search for
* @param {string} searchParam
* @param {Object} previousResult a previous result to use for faster searchinig
* @param {Object} listener the listener to notify when the search is complete
*/
startSearch(searchString, searchParam, previousResult, listener) {
// TODO: These mock data should be replaced by form autofill API
let labels = ["Mary", "John"];
let values = ["Mary S.", "John S."];
let comments = ["123 Sesame Street.", "331 E. Evelyn Avenue"];
let result = new FormAutoCompleteResult(searchString,
Ci.nsIAutoCompleteResult.RESULT_SUCCESS,
0, "", values, labels,
comments);
listener.onSearchResult(this, result);
},
/**
* Stops an asynchronous search that is in progress
*/
stopSearch() {
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AutofillProfileAutoCompleteSearch]);
// TODO: Remove this lint option once we apply ProfileAutocomplete while
// content script initialization.
/* eslint no-unused-vars: [2, {"vars": "local"}] */
let ProfileAutocomplete = {
_registered: false,
_factory: null,
ensureRegistered() {
if (this._registered) {
return;
}
this._factory = new AutocompleteFactory();
this._factory.register(AutofillProfileAutoCompleteSearch);
this._registered = true;
},
ensureUnregistered() {
if (!this._registered) {
return;
}
this._factory.unregister();
this._factory = null;
this._registered = false;
},
};

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

@ -48,6 +48,7 @@
#PopupAutoComplete > richlistbox > richlistitem[originaltype="insecureWarning"][selected] {
background-color: var(--arrowpanel-dimmed-further);
color: -moz-DialogText;
}
#PopupAutoComplete > richlistbox > richlistitem[originaltype="insecureWarning"] > .ac-title {

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

@ -5,9 +5,9 @@
"use strict";
const {
TOGGLE_FILTER_TYPE,
ENABLE_FILTER_TYPE_ONLY,
SET_FILTER_TEXT,
TOGGLE_REQUEST_FILTER_TYPE,
ENABLE_REQUEST_FILTER_TYPE_ONLY,
SET_REQUEST_FILTER_TEXT,
} = require("../constants");
/**
@ -17,9 +17,9 @@ const {
*
* @param {string} filter - A filter type is going to be updated
*/
function toggleFilterType(filter) {
function toggleRequestFilterType(filter) {
return {
type: TOGGLE_FILTER_TYPE,
type: TOGGLE_REQUEST_FILTER_TYPE,
filter,
};
}
@ -32,9 +32,9 @@ function toggleFilterType(filter) {
*
* @param {string} filter - A filter type is going to be updated
*/
function enableFilterTypeOnly(filter) {
function enableRequestFilterTypeOnly(filter) {
return {
type: ENABLE_FILTER_TYPE_ONLY,
type: ENABLE_REQUEST_FILTER_TYPE_ONLY,
filter,
};
}
@ -44,15 +44,15 @@ function enableFilterTypeOnly(filter) {
*
* @param {string} text - A filter text is going to be set
*/
function setFilterText(text) {
function setRequestFilterText(text) {
return {
type: SET_FILTER_TEXT,
type: SET_REQUEST_FILTER_TEXT,
text,
};
}
module.exports = {
toggleFilterType,
enableFilterTypeOnly,
setFilterText,
toggleRequestFilterType,
enableRequestFilterTypeOnly,
setRequestFilterText,
};

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

@ -12,10 +12,10 @@ const Actions = require("../actions/index");
const { button, div } = DOM;
function FilterButtons({
filterTypes,
triggerFilterType,
requestFilterTypes,
toggleRequestFilterType,
}) {
const buttons = filterTypes.entrySeq().map(([type, checked]) => {
const buttons = requestFilterTypes.entrySeq().map(([type, checked]) => {
let classList = ["menu-filter-button"];
checked && classList.push("checked");
@ -23,8 +23,8 @@ function FilterButtons({
id: `requests-menu-filter-${type}-button`,
className: classList.join(" "),
"data-key": type,
onClick: triggerFilterType,
onKeyDown: triggerFilterType,
onClick: toggleRequestFilterType,
onKeyDown: toggleRequestFilterType,
}, L10N.getStr(`netmonitor.toolbar.filter.${type}`));
}).toArray();
@ -33,17 +33,17 @@ function FilterButtons({
FilterButtons.propTypes = {
state: PropTypes.object.isRequired,
triggerFilterType: PropTypes.func.iRequired,
toggleRequestFilterType: PropTypes.func.iRequired,
};
module.exports = connect(
(state) => ({ filterTypes: state.filters.types }),
(state) => ({ requestFilterTypes: state.filters.requestFilterTypes }),
(dispatch) => ({
triggerFilterType: (evt) => {
toggleRequestFilterType: (evt) => {
if (evt.type === "keydown" && (evt.key !== "" || evt.key !== "Enter")) {
return;
}
dispatch(Actions.toggleFilterType(evt.target.dataset.key));
dispatch(Actions.toggleRequestFilterType(evt.target.dataset.key));
},
})
)(FilterButtons);

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

@ -19,7 +19,7 @@ module.exports = connect(
}),
(dispatch) => ({
onChange: (url) => {
dispatch(Actions.setFilterText(url));
dispatch(Actions.setRequestFilterText(url));
},
})
)(SearchBox);

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

@ -18,15 +18,15 @@ const actionTypes = {
CLEAR_REQUESTS: "CLEAR_REQUESTS",
CLEAR_TIMING_MARKERS: "CLEAR_TIMING_MARKERS",
CLONE_SELECTED_REQUEST: "CLONE_SELECTED_REQUEST",
ENABLE_FILTER_TYPE_ONLY: "ENABLE_FILTER_TYPE_ONLY",
ENABLE_REQUEST_FILTER_TYPE_ONLY: "ENABLE_REQUEST_FILTER_TYPE_ONLY",
OPEN_SIDEBAR: "OPEN_SIDEBAR",
OPEN_STATISTICS: "OPEN_STATISTICS",
PRESELECT_REQUEST: "PRESELECT_REQUEST",
REMOVE_SELECTED_CUSTOM_REQUEST: "REMOVE_SELECTED_CUSTOM_REQUEST",
SELECT_REQUEST: "SELECT_REQUEST",
SET_FILTER_TEXT: "SET_FILTER_TEXT",
SET_REQUEST_FILTER_TEXT: "SET_REQUEST_FILTER_TEXT",
SORT_BY: "SORT_BY",
TOGGLE_FILTER_TYPE: "TOGGLE_FILTER_TYPE",
TOGGLE_REQUEST_FILTER_TYPE: "TOGGLE_REQUEST_FILTER_TYPE",
UPDATE_REQUEST: "UPDATE_REQUEST",
WATERFALL_RESIZE: "WATERFALL_RESIZE",
};

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

@ -266,7 +266,7 @@ var NetMonitorController = {
request = getDisplayedRequestById(gStore.getState(), requestId);
if (!request) {
// Reset filters so that the request is visible.
gStore.dispatch(Actions.toggleFilterType("all"));
gStore.dispatch(Actions.toggleRequestFilterType("all"));
request = getDisplayedRequestById(gStore.getState(), requestId);
}

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

@ -6,9 +6,9 @@
const I = require("devtools/client/shared/vendor/immutable");
const {
TOGGLE_FILTER_TYPE,
ENABLE_FILTER_TYPE_ONLY,
SET_FILTER_TEXT,
TOGGLE_REQUEST_FILTER_TYPE,
ENABLE_REQUEST_FILTER_TYPE_ONLY,
SET_REQUEST_FILTER_TEXT,
} = require("../constants");
const FilterTypes = I.Record({
@ -26,11 +26,11 @@ const FilterTypes = I.Record({
});
const Filters = I.Record({
types: new FilterTypes({ all: true }),
text: "",
requestFilterTypes: new FilterTypes({ all: true }),
requestFilterText: "",
});
function toggleFilterType(state, action) {
function toggleRequestFilterType(state, action) {
let { filter } = action;
let newState;
@ -54,7 +54,7 @@ function toggleFilterType(state, action) {
return newState;
}
function enableFilterTypeOnly(state, action) {
function enableRequestFilterTypeOnly(state, action) {
let { filter } = action;
// Ignore unknown filter type
@ -67,12 +67,14 @@ function enableFilterTypeOnly(state, action) {
function filters(state = new Filters(), action) {
switch (action.type) {
case TOGGLE_FILTER_TYPE:
return state.set("types", toggleFilterType(state.types, action));
case ENABLE_FILTER_TYPE_ONLY:
return state.set("types", enableFilterTypeOnly(state.types, action));
case SET_FILTER_TEXT:
return state.set("text", action.text);
case TOGGLE_REQUEST_FILTER_TYPE:
return state.set("requestFilterTypes",
toggleRequestFilterType(state.requestFilterTypes, action));
case ENABLE_REQUEST_FILTER_TYPE_ONLY:
return state.set("requestFilterTypes",
enableRequestFilterTypeOnly(state.requestFilterTypes, action));
case SET_REQUEST_FILTER_TEXT:
return state.set("requestFilterText", action.text);
default:
return state;
}

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

@ -72,7 +72,7 @@ RequestsMenuView.prototype = {
this.contextMenu = new RequestListContextMenu();
this.contextMenu.initialize(store);
Prefs.filters.forEach(type => store.dispatch(Actions.toggleFilterType(type)));
Prefs.filters.forEach(type => store.dispatch(Actions.toggleRequestFilterType(type)));
// Watch selection changes
this.store.subscribe(storeWatcher(

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

@ -5,7 +5,8 @@
"use strict";
function getActiveFilters(state) {
return state.filters.types.toSeq().filter(checked => checked).keySeq().toArray();
return state.filters.requestFilterTypes.toSeq()
.filter(checked => checked).keySeq().toArray();
}
module.exports = {

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

@ -24,10 +24,10 @@ function getOrigRequest(requests, req) {
const getFilterFn = createSelector(
state => state.filters,
filters => r => {
const matchesType = filters.types.some((enabled, filter) => {
const matchesType = filters.requestFilterTypes.some((enabled, filter) => {
return enabled && Filters[filter] && Filters[filter](r);
});
return matchesType && isFreetextMatch(r, filters.text);
return matchesType && isFreetextMatch(r, filters.requestFilterText);
}
);

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

@ -171,7 +171,7 @@ StatisticsView.prototype = {
chart.on("click", (_, item) => {
// Reset FilterButtons and enable one filter exclusively
this.store.dispatch(Actions.enableFilterTypeOnly(item.label));
this.store.dispatch(Actions.enableRequestFilterTypeOnly(item.label));
this.store.dispatch(Actions.openStatistics(false));
});

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

@ -135,7 +135,7 @@ add_task(function* () {
let { gStore } = monitor.panelWin;
function setFreetextFilter(value) {
gStore.dispatch(Actions.setFilterText(value));
gStore.dispatch(Actions.setRequestFilterText(value));
}
info("Starting test... ");

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

@ -28,7 +28,7 @@ add_task(function* () {
info("Checking the image thumbnail when all items are sorted.");
checkImageThumbnail();
gStore.dispatch(Actions.toggleFilterType("images"));
gStore.dispatch(Actions.toggleRequestFilterType("images"));
info("Checking the image thumbnail when only images are shown.");
checkImageThumbnail();

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

@ -34,7 +34,7 @@ add_task(function* () {
// Predicate used to modify the frontend when setting the new pref value,
// before trying to validate the changes.
modifyFrontend: ($, value) => value.forEach(e =>
getStore().dispatch(Actions.toggleFilterType(e)))
getStore().dispatch(Actions.toggleRequestFilterType(e)))
},
networkDetailsWidth: {
newValue: ~~(Math.random() * 200 + 100),

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

@ -57,7 +57,7 @@ describe("FilterButtons::enableFilterOnly:", () => {
FilterButtons()
));
store.dispatch(Actions.enableFilterTypeOnly("xhr"));
store.dispatch(Actions.enableRequestFilterTypeOnly("xhr"));
asExpected(wrapper, expectXHRTypes, `when enableFilterOnly("xhr") is called`);
});
@ -83,8 +83,8 @@ describe("FilterButtons::toggleFilter:", () => {
FilterButtons()
));
store.dispatch(Actions.toggleFilterType("xhr"));
store.dispatch(Actions.toggleFilterType("js"));
store.dispatch(Actions.toggleRequestFilterType("xhr"));
store.dispatch(Actions.toggleRequestFilterType("js"));
asExpected(wrapper, expectXHRJSTypes, `when xhr, js is toggled`);
});

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

@ -47,7 +47,7 @@ add_task(function* () {
"The correct request is definitely selected");
// Filter out the HTML request.
panel.panelWin.gStore.dispatch(Actions.toggleFilterType("js"));
panel.panelWin.gStore.dispatch(Actions.toggleRequestFilterType("js"));
yield toolbox.selectTool("webconsole");
is(toolbox.currentToolId, "webconsole", "Web console was selected");

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

@ -441,6 +441,25 @@ var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
return promise.resolve(content);
}
return this.fetchStylesheet(this.href).then(({ content }) => {
this.text = content;
return content;
});
},
/**
* Fetch a stylesheet at the provided URL. Returns a promise that will resolve the
* result of the fetch command.
*
* @param {String} href
* The href of the stylesheet to retrieve.
* @return {Promise} a promise that resolves with an object with the following members
* on success:
* - content: the document at that URL, as a string,
* - contentType: the content type of the document
* If an error occurs, the promise is rejected with that error.
*/
fetchStylesheet: Task.async(function* (href) {
let options = {
loadFromCache: true,
policy: Ci.nsIContentPolicy.TYPE_INTERNAL_STYLESHEET,
@ -451,19 +470,30 @@ var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
// stylesheets instead of the content principal since such stylesheets
// require system principal to load. At meanwhile, we strip the loadGroup
// for preventing the assertion of the userContextId mismatching.
// The default internal stylesheets load from the 'resource:' URL.
// Bug 1287607, 1291321 - 'chrome' and 'file' protocols should also be handled in the
// same way.
if (!/^(chrome|file|resource):\/\//.test(this.href)) {
// chrome|file|resource|moz-extension protocols rely on the system principal.
let excludedProtocolsRe = /^(chrome|file|resource|moz-extension):\/\//;
if (!excludedProtocolsRe.test(this.href)) {
// Stylesheets using other protocols should use the content principal.
options.window = this.window;
options.principal = this.document.nodePrincipal;
}
return fetch(this.href, options).then(({ content }) => {
this.text = content;
return content;
});
},
let result;
try {
result = yield fetch(this.href, options);
} catch (e) {
// The list of excluded protocols can be missing some protocols, try to use the
// system principal if the first fetch failed.
console.error(`stylesheets actor: fetch failed for ${this.href},` +
` using system principal instead.`);
options.window = undefined;
options.principal = undefined;
result = yield fetch(this.href, options);
}
return result;
}),
/**
* Protocol method to get the original source (actors) for this

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

@ -2857,6 +2857,7 @@ exports.CSS_PROPERTIES = {
"box-shadow",
"box-sizing",
"caption-side",
"caret-color",
"clear",
"clip",
"clip-path",
@ -5261,6 +5262,28 @@ exports.CSS_PROPERTIES = {
"unset"
]
},
"caret-color": {
"isInherited": true,
"subproperties": [
"caret-color"
],
"supports": [
2
],
"values": [
"COLOR",
"auto",
"currentColor",
"hsl",
"hsla",
"inherit",
"initial",
"rgb",
"rgba",
"transparent",
"unset"
]
},
"clear": {
"isInherited": false,
"subproperties": [

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

@ -486,13 +486,13 @@ public:
void HandleAudioDecoded(MediaData* aAudio) override
{
mMaster->Push(aAudio);
mMaster->PushAudio(aAudio);
MaybeFinishDecodeFirstFrame();
}
void HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) override
{
mMaster->Push(aVideo);
mMaster->PushVideo(aVideo);
MaybeFinishDecodeFirstFrame();
}
@ -579,13 +579,15 @@ public:
void HandleAudioDecoded(MediaData* aAudio) override
{
mMaster->Push(aAudio);
mMaster->PushAudio(aAudio);
mMaster->DispatchDecodeTasksIfNeeded();
MaybeStopPrerolling();
}
void HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) override
{
mMaster->Push(aVideo);
mMaster->PushVideo(aVideo);
mMaster->DispatchDecodeTasksIfNeeded();
MaybeStopPrerolling();
CheckSlowDecoding(aDecodeStart);
}
@ -867,7 +869,7 @@ public:
// requests when AccurateSeekTask::Seek() begins. We will just store the data
// without checking |mDiscontinuity| or calling DropAudioUpToSeekTarget().
if (mSeekJob.mTarget->IsVideoOnly()) {
mMaster->Push(aAudio);
mMaster->PushAudio(aAudio);
return;
}
@ -875,7 +877,7 @@ public:
if (mSeekJob.mTarget->IsFast()) {
// Non-precise seek; we can stop the seek at the first sample.
mMaster->Push(aAudio);
mMaster->PushAudio(aAudio);
mDoneAudioSeeking = true;
} else {
nsresult rv = DropAudioUpToSeekTarget(aAudio->As<AudioData>());
@ -901,7 +903,7 @@ public:
if (mSeekJob.mTarget->IsFast()) {
// Non-precise seek. We can stop the seek at the first sample.
mMaster->Push(aVideo);
mMaster->PushVideo(aVideo);
mDoneVideoSeeking = true;
} else {
nsresult rv = DropVideoUpToSeekTarget(aVideo);
@ -948,13 +950,13 @@ public:
AudioQueue().Finish();
mDoneAudioSeeking = true;
} else {
VideoQueue().Finish();
mDoneVideoSeeking = true;
if (mFirstVideoFrameAfterSeek) {
// Hit the end of stream. Move mFirstVideoFrameAfterSeek into
// mSeekedVideoData so we have something to display after seeking.
mMaster->Push(mFirstVideoFrameAfterSeek);
mMaster->PushVideo(mFirstVideoFrameAfterSeek);
}
VideoQueue().Finish();
mDoneVideoSeeking = true;
}
MaybeFinishSeek();
return;
@ -1149,7 +1151,7 @@ private:
// silence to cover the gap. Typically this happens in poorly muxed
// files.
SWARN("Audio not synced after seek, maybe a poorly muxed file?");
mMaster->Push(aAudio);
mMaster->PushAudio(aAudio);
mDoneAudioSeeking = true;
return NS_OK;
}
@ -1195,7 +1197,7 @@ private:
channels,
aAudio->mRate));
MOZ_ASSERT(AudioQueue().GetSize() == 0, "Should be the 1st sample after seeking");
mMaster->Push(data);
mMaster->PushAudio(data);
mDoneAudioSeeking = true;
return NS_OK;
@ -1227,7 +1229,7 @@ private:
video->mTime, video->GetEndTime(), target);
MOZ_ASSERT(VideoQueue().GetSize() == 0, "Should be the 1st sample after seeking");
mMaster->Push(video);
mMaster->PushVideo(video);
mDoneVideoSeeking = true;
}
@ -1361,7 +1363,7 @@ private:
void HandleAudioDecoded(MediaData* aAudio) override
{
mMaster->Push(aAudio);
mMaster->PushAudio(aAudio);
}
void HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) override
@ -1371,7 +1373,7 @@ private:
MOZ_ASSERT(NeedMoreVideo());
if (aVideo->mTime > mCurrentTime) {
mMaster->Push(aVideo);
mMaster->PushVideo(aVideo);
FinishSeek();
} else {
RequestVideoData();
@ -1550,7 +1552,7 @@ public:
{
// This might be the sample we need to exit buffering.
// Schedule Step() to check it.
mMaster->Push(aAudio);
mMaster->PushAudio(aAudio);
mMaster->ScheduleStateMachine();
}
@ -1558,7 +1560,7 @@ public:
{
// This might be the sample we need to exit buffering.
// Schedule Step() to check it.
mMaster->Push(aVideo);
mMaster->PushVideo(aVideo);
mMaster->ScheduleStateMachine();
}
@ -2163,6 +2165,7 @@ BufferingState::Step()
SLOG("Buffering: wait %ds, timeout in %.3lfs",
mBufferingWait, mBufferingWait - elapsed.ToSeconds());
mMaster->ScheduleStateMachineIn(USECS_PER_S);
mMaster->DispatchDecodeTasksIfNeeded();
return;
}
} else if (mMaster->OutOfDecodedAudio() || mMaster->OutOfDecodedVideo()) {
@ -2549,25 +2552,20 @@ MediaDecoderStateMachine::NeedToDecodeAudio()
}
void
MediaDecoderStateMachine::Push(MediaData* aSample)
MediaDecoderStateMachine::PushAudio(MediaData* aSample)
{
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(aSample);
AudioQueue().Push(aSample);
}
if (aSample->mType == MediaData::AUDIO_DATA) {
// TODO: Send aSample to MSG and recalculate readystate before pushing,
// otherwise AdvanceFrame may pop the sample before we have a chance
// to reach playing.
AudioQueue().Push(aSample);
} else if (aSample->mType == MediaData::VIDEO_DATA) {
// TODO: Send aSample to MSG and recalculate readystate before pushing,
// otherwise AdvanceFrame may pop the sample before we have a chance
// to reach playing.
aSample->As<VideoData>()->mFrameID = ++mCurrentFrameID;
VideoQueue().Push(aSample);
}
DispatchDecodeTasksIfNeeded();
void
MediaDecoderStateMachine::PushVideo(MediaData* aSample)
{
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(aSample);
aSample->As<VideoData>()->mFrameID = ++mCurrentFrameID;
VideoQueue().Push(aSample);
}
void

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

@ -338,7 +338,8 @@ protected:
// Inserts MediaData* samples into their respective MediaQueues.
// aSample must not be null.
void Push(MediaData* aSample);
void PushAudio(MediaData* aSample);
void PushVideo(MediaData* aSample);
void OnAudioPopped(const RefPtr<MediaData>& aSample);
void OnVideoPopped(const RefPtr<MediaData>& aSample);

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

@ -17,7 +17,6 @@
#include "HTMLEditRules.h"
#include "HTMLEditUtils.h"
#include "HTMLURIRefObject.h"
#include "SetDocumentTitleTransaction.h"
#include "StyleSheetTransactions.h"
#include "TextEditUtils.h"
#include "TypeInState.h"
@ -811,22 +810,6 @@ HTMLEditor::IsBlockNode(nsINode* aNode)
return aNode && NodeIsBlockStatic(aNode);
}
// Non-static version for the nsIEditor interface and JavaScript
NS_IMETHODIMP
HTMLEditor::SetDocumentTitle(const nsAString& aTitle)
{
RefPtr<SetDocumentTitleTransaction> transaction =
new SetDocumentTitleTransaction();
NS_ENSURE_TRUE(transaction, NS_ERROR_OUT_OF_MEMORY);
nsresult rv = transaction->Init(this, &aTitle);
NS_ENSURE_SUCCESS(rv, rv);
//Don't let Rules System change the selection
AutoTransactionsConserveSelection dontChangeSelection(this);
return EditorBase::DoTransaction(transaction);
}
/**
* GetBlockNodeParent returns enclosing block level ancestor, if any.
*/

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

@ -1,230 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include "SetDocumentTitleTransaction.h"
#include "mozilla/dom/Element.h" // for Element
#include "nsAString.h"
#include "nsCOMPtr.h" // for nsCOMPtr, getter_AddRefs, etc.
#include "nsDebug.h" // for NS_ENSURE_SUCCESS, etc.
#include "nsError.h" // for NS_OK, NS_ERROR_FAILURE, etc.
#include "nsIDOMCharacterData.h" // for nsIDOMCharacterData
#include "nsIDOMDocument.h" // for nsIDOMDocument
#include "nsIDOMElement.h" // for nsIDOMElement
#include "nsIDOMNode.h" // for nsIDOMNode
#include "nsIDOMNodeList.h" // for nsIDOMNodeList
#include "nsIDOMText.h" // for nsIDOMText
#include "nsIDocument.h" // for nsIDocument
#include "nsIEditor.h" // for nsIEditor
#include "nsIHTMLEditor.h" // for nsIHTMLEditor
#include "nsLiteralString.h" // for NS_LITERAL_STRING
#include "nsTextNode.h" // for nsTextNode
#include "nsQueryObject.h" // for do_QueryObject
namespace mozilla {
// Note that aEditor is not refcounted.
SetDocumentTitleTransaction::SetDocumentTitleTransaction()
: mEditor(nullptr)
, mIsTransient(false)
{
}
NS_IMETHODIMP
SetDocumentTitleTransaction::Init(nsIHTMLEditor* aEditor,
const nsAString* aValue)
{
NS_ASSERTION(aEditor && aValue, "null args");
if (!aEditor || !aValue) {
return NS_ERROR_NULL_POINTER;
}
mEditor = aEditor;
mValue = *aValue;
return NS_OK;
}
NS_IMETHODIMP
SetDocumentTitleTransaction::DoTransaction()
{
return SetDomTitle(mValue);
}
NS_IMETHODIMP
SetDocumentTitleTransaction::UndoTransaction()
{
// No extra work required; the DOM changes alone are enough
return NS_OK;
}
NS_IMETHODIMP
SetDocumentTitleTransaction::RedoTransaction()
{
// No extra work required; the DOM changes alone are enough
return NS_OK;
}
nsresult
SetDocumentTitleTransaction::SetDomTitle(const nsAString& aTitle)
{
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
if (NS_WARN_IF(!editor)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMDocument> domDoc;
nsresult rv = editor->GetDocument(getter_AddRefs(domDoc));
if (NS_WARN_IF(!domDoc)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMNodeList> titleList;
rv = domDoc->GetElementsByTagName(NS_LITERAL_STRING("title"),
getter_AddRefs(titleList));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// First assume we will NOT really do anything
// (transaction will not be pushed on stack)
mIsTransient = true;
nsCOMPtr<nsIDOMNode> titleNode;
if(titleList) {
rv = titleList->Item(0, getter_AddRefs(titleNode));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (titleNode) {
// Delete existing child textnode of title node
// (Note: all contents under a TITLE node are always in a single text node)
nsCOMPtr<nsIDOMNode> child;
rv = titleNode->GetFirstChild(getter_AddRefs(child));
if (NS_FAILED(rv)) {
return rv;
}
if(child) {
// Save current text as the undo value
nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(child);
if(textNode) {
textNode->GetData(mUndoValue);
// If title text is identical to what already exists,
// quit now (mIsTransient is now TRUE)
if (mUndoValue == aTitle) {
return NS_OK;
}
}
rv = editor->DeleteNode(child);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
}
}
// We didn't return above, thus we really will be changing the title
mIsTransient = false;
// Get the <HEAD> node, create a <TITLE> and insert it under the HEAD
nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc);
if (NS_WARN_IF(!document)) {
return NS_ERROR_UNEXPECTED;
}
RefPtr<dom::Element> headElement = document->GetHeadElement();
if (NS_WARN_IF(!headElement)) {
return NS_ERROR_UNEXPECTED;
}
bool newTitleNode = false;
uint32_t newTitleIndex = 0;
if (!titleNode) {
// Didn't find one above: Create a new one
nsCOMPtr<nsIDOMElement>titleElement;
rv = domDoc->CreateElement(NS_LITERAL_STRING("title"),
getter_AddRefs(titleElement));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (NS_WARN_IF(!titleElement)) {
return NS_ERROR_FAILURE;
}
titleNode = do_QueryInterface(titleElement);
newTitleNode = true;
// Get index so we append new title node after all existing HEAD children.
newTitleIndex = headElement->GetChildCount();
}
// Append a text node under the TITLE only if the title text isn't empty.
if (titleNode && !aTitle.IsEmpty()) {
RefPtr<nsTextNode> textNode = document->CreateTextNode(aTitle);
if (newTitleNode) {
// Not undoable: We will insert newTitleNode below
nsCOMPtr<nsINode> title = do_QueryInterface(titleNode);
MOZ_ASSERT(title);
ErrorResult result;
title->AppendChild(*textNode, result);
if (NS_WARN_IF(result.Failed())) {
return result.StealNSResult();
}
} else {
// This is an undoable transaction
nsCOMPtr<nsIDOMNode> newNode = do_QueryObject(textNode);
if (NS_WARN_IF(!newNode)) {
return NS_ERROR_FAILURE;
}
rv = editor->InsertNode(newNode, titleNode, 0);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
// Calling AppendChild() or InsertNode() could cause removing the head
// element. So, let's mark it dirty.
headElement = nullptr;
}
if (newTitleNode) {
if (!headElement) {
headElement = document->GetHeadElement();
if (NS_WARN_IF(!headElement)) {
// XXX Can we return NS_OK when there is no head element?
return NS_ERROR_UNEXPECTED;
}
}
// Undoable transaction to insert title+text together
rv = editor->InsertNode(titleNode, headElement->AsDOMNode(), newTitleIndex);
}
return rv;
}
NS_IMETHODIMP
SetDocumentTitleTransaction::GetTxnDescription(nsAString& aString)
{
aString.AssignLiteral("SetDocumentTitleTransaction: ");
aString += mValue;
return NS_OK;
}
NS_IMETHODIMP
SetDocumentTitleTransaction::GetIsTransient(bool* aIsTransient)
{
if (NS_WARN_IF(!aIsTransient)) {
return NS_ERROR_NULL_POINTER;
}
*aIsTransient = mIsTransient;
return NS_OK;
}
} // namespace mozilla

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

@ -1,60 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef SetDocumentTitleTransaction_h
#define SetDocumentTitleTransaction_h
#include "mozilla/EditTransactionBase.h" // for EditTransactionBase, etc.
#include "nsString.h" // for nsString
#include "nscore.h" // for NS_IMETHOD, nsAString, etc.
class nsIHTMLEditor;
namespace mozilla {
/**
* A transaction that changes the document's title,
* which is a text node under the <title> tag in a page's <head> section
* provides default concrete behavior for all nsITransaction methods.
*/
class SetDocumentTitleTransaction final : public EditTransactionBase
{
public:
/**
* Initialize the transaction.
* @param aEditor The object providing core editing operations.
* @param aValue The new value for document title.
*/
NS_IMETHOD Init(nsIHTMLEditor* aEditor,
const nsAString* aValue);
SetDocumentTitleTransaction();
private:
nsresult SetDomTitle(const nsAString& aTitle);
public:
NS_DECL_EDITTRANSACTIONBASE
NS_IMETHOD RedoTransaction() override;
NS_IMETHOD GetIsTransient(bool *aIsTransient) override;
protected:
// The editor that created this transaction.
nsIHTMLEditor* mEditor;
// The new title string.
nsString mValue;
// The previous title string to use for undo.
nsString mUndoValue;
// Set true if we dont' really change the title during Do().
bool mIsTransient;
};
} // namespace mozilla
#endif // #ifndef SetDocumentTitleTransaction_h

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

@ -64,7 +64,6 @@ UNIFIED_SOURCES += [
'JoinNodeTransaction.cpp',
'PlaceholderTransaction.cpp',
'SelectionState.cpp',
'SetDocumentTitleTransaction.cpp',
'SplitNodeTransaction.cpp',
'StyleSheetTransactions.cpp',
'TextEditor.cpp',

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

@ -9,6 +9,5 @@ support-files = green.png
[test_bug780908.xul]
[test_contenteditable_text_input_handling.html]
[test_htmleditor_keyevent_handling.html]
[test_set_document_title_transaction.html]
[test_texteditor_keyevent_handling.html]
skip-if = (debug && os=='win') || (os == 'linux') # Bug 1116205, leaks on windows debug, fails delete key on linux

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

@ -1,79 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Test for SetDocumentTitleTransaction</title>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body onload="runTests()">
<div id="display">
<iframe src="data:text/html,<!DOCTYPE html><html><head><title>first title</title></head><body></body></html>"></iframe>
</div>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
<script class="testbody" type="application/javascript">
function runTests() {
var iframe = document.getElementsByTagName("iframe")[0];
function isDocumentTitleEquals(aDescription, aExpectedTitle) {
is(iframe.contentDocument.title, aExpectedTitle, aDescription + ": document.title should be " + aExpectedTitle);
is(iframe.contentDocument.getElementsByTagName("title")[0].textContent, aExpectedTitle, aDescription + ": The text in the title element should be " + aExpectedTitle);
}
isDocumentTitleEquals("Checking isDocumentTitleEquals()", "first title");
const kTests = [
{ description: "designMode=\"on\"",
init: function () {
iframe.contentDocument.designMode = "on";
},
cleanUp: function () {
iframe.contentDocument.designMode = "off";
}
},
{ description: "html element has contenteditable attribute",
init: function () {
iframe.contentDocument.documentElement.setAttribute("contenteditable", "true");
},
cleanUp: function () {
iframe.contentDocument.documentElement.removeAttribute("contenteditable");
}
},
];
for (var i = 0; i < kTests.length; i++) {
const kTest = kTests[i];
kTest.init();
var editor = SpecialPowers.wrap(iframe.contentWindow).
QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor).
getInterface(SpecialPowers.Ci.nsIWebNavigation).
QueryInterface(SpecialPowers.Ci.nsIDocShell).editor;
ok(editor, kTest.description + ": The docshell should have editor");
var htmlEditor = editor.QueryInterface(SpecialPowers.Ci.nsIHTMLEditor);
ok(htmlEditor, kTest.description + ": The editor should have nsIHTMLEditor interface");
// Replace existing title.
htmlEditor.setDocumentTitle("Modified title");
isDocumentTitleEquals(kTest.description, "Modified title");
// When the document doesn't have <title> element, title element should be created automatically.
iframe.contentDocument.head.removeChild(iframe.contentDocument.getElementsByTagName("title")[0]);
is(iframe.contentDocument.getElementsByTagName("title").length, 0, kTest.description + ": There should be no title element");
htmlEditor.setDocumentTitle("new title");
is(iframe.contentDocument.getElementsByTagName("title").length, 1, kTest.description + ": There should be a title element");
isDocumentTitleEquals(kTest.description, "new title");
kTest.cleanUp();
}
SimpleTest.finish();
}
</script>
</body>
</html>

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

@ -236,11 +236,6 @@ interface nsIHTMLEditor : nsISupports
void insertElementAtSelection(in nsIDOMElement aElement,
in boolean aDeleteSelection);
/**
* Set the documents title.
*/
void setDocumentTitle(in AString aTitle);
/**
* Set the BaseURL for the document to the current URL
* but only if the page doesn't have a <base> tag

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

@ -1882,8 +1882,7 @@ nsIFrame::DisplayCaret(nsDisplayListBuilder* aBuilder,
nscolor
nsIFrame::GetCaretColorAt(int32_t aOffset)
{
// Use text color.
return StyleColor()->mColor;
return StyleColor()->CalcComplexColor(StyleUserInterface()->mCaretColor);
}
bool

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

@ -0,0 +1,18 @@
<!DOCTYPE html>
<style>
@font-face {
font-family: Ahem;
src: url(../fonts/Ahem.ttf);
}
div {
font: 16px/1 Ahem;
width: 1em;
background: green;
}
</style>
<div><span></span></div>
<script>
let $div = document.querySelector('div');
let $span = document.querySelector('span');
$div.style.height = $span.getBoundingClientRect().height + 'px';
</script>

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

@ -0,0 +1,17 @@
<!DOCTYPE html>
<style>
@font-face {
font-family: Ahem;
src: url(../fonts/Ahem.ttf);
}
textarea {
caret-color: green;
font: 16px/1 Ahem;
outline: none;
border: 0 none;
resize: none;
padding: 0;
margin: 0;
}
</style>
<textarea autofocus></textarea>

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

@ -0,0 +1 @@
pref(ui.caretWidth,16) needs-focus == caret-color-01.html caret-color-01-ref.html

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

@ -130,6 +130,9 @@ include css-sizing/reftest.list
# css transitions
include css-transitions/reftest.list
# css ui
include css-ui/reftest.list
# css :-moz-ui-invalid
include css-ui-invalid/reftest.list

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

@ -4730,8 +4730,12 @@ StyleAnimationValue::ExtractComputedValue(nsCSSPropertyID aProperty,
StyleDataAtOffset<nscolor>(styleStruct, ssOffset));
return true;
case eStyleAnimType_ComplexColor: {
aComputedValue.SetComplexColorValue(
StyleDataAtOffset<StyleComplexColor>(styleStruct, ssOffset));
auto& color = StyleDataAtOffset<StyleComplexColor>(styleStruct, ssOffset);
if (color.mIsAuto) {
aComputedValue.SetAutoValue();
} else {
aComputedValue.SetComplexColorValue(color);
}
return true;
}
case eStyleAnimType_PaintServer: {
@ -5048,7 +5052,9 @@ StyleAnimationValue::SetCurrentColorValue()
void
StyleAnimationValue::SetComplexColorValue(const StyleComplexColor& aColor)
{
if (aColor.IsCurrentColor()) {
if (aColor.mIsAuto) {
SetAutoValue();
} else if (aColor.IsCurrentColor()) {
SetCurrentColorValue();
} else if (aColor.IsNumericColor()) {
SetColorValue(aColor.mColor);

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

@ -24,16 +24,29 @@ struct StyleComplexColor
{
nscolor mColor;
uint8_t mForegroundRatio;
// Whether the complex color represents a computed-value time auto
// value. This is only a flag indicating that this value should not
// be interpolatable with other colors, while other fields still
// represents the actual used color of this value.
bool mIsAuto;
static StyleComplexColor FromColor(nscolor aColor) { return {aColor, 0}; }
static StyleComplexColor CurrentColor() { return {NS_RGBA(0, 0, 0, 0), 255}; }
static StyleComplexColor FromColor(nscolor aColor) {
return {aColor, 0, false};
}
static StyleComplexColor CurrentColor() {
return {NS_RGBA(0, 0, 0, 0), 255, false};
}
static StyleComplexColor Auto() {
return {NS_RGBA(0, 0, 0, 0), 255, true};
}
bool IsNumericColor() const { return mForegroundRatio == 0; }
bool IsCurrentColor() const { return mForegroundRatio == 255; }
bool operator==(const StyleComplexColor& aOther) const {
return mForegroundRatio == aOther.mForegroundRatio &&
(IsCurrentColor() || mColor == aOther.mColor);
(IsCurrentColor() || mColor == aOther.mColor) &&
mIsAuto == aOther.mIsAuto;
}
bool operator!=(const StyleComplexColor& aOther) const {
return !(*this == aOther);

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

@ -1381,6 +1381,17 @@ CSS_PROP_TABLEBORDER(
kCaptionSideKTable,
CSS_PROP_NO_OFFSET,
eStyleAnimType_Discrete)
CSS_PROP_USERINTERFACE(
caret-color,
caret_color,
CaretColor,
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
"",
VARIANT_AUTO | VARIANT_HC,
nullptr,
offsetof(nsStyleUserInterface, mCaretColor),
eStyleAnimType_ComplexColor)
CSS_PROP_DISPLAY(
clear,
clear,

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

@ -4143,6 +4143,14 @@ nsComputedDOMStyle::DoGetUnicodeBidi()
return val.forget();
}
already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetCaretColor()
{
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
SetValueFromComplexColor(val, StyleUserInterface()->mCaretColor);
return val.forget();
}
already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetCursor()
{

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

@ -482,6 +482,7 @@ private:
already_AddRefed<CSSValue> DoGetShapeOutside();
/* User interface properties */
already_AddRefed<CSSValue> DoGetCaretColor();
already_AddRefed<CSSValue> DoGetCursor();
already_AddRefed<CSSValue> DoGetForceBrokenImageIcon();
already_AddRefed<CSSValue> DoGetIMEMode();

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

@ -101,6 +101,7 @@ COMPUTED_STYLE_PROP(box_decoration_break, BoxDecorationBreak)
COMPUTED_STYLE_PROP(box_shadow, BoxShadow)
COMPUTED_STYLE_PROP(box_sizing, BoxSizing)
COMPUTED_STYLE_PROP(caption_side, CaptionSide)
COMPUTED_STYLE_PROP(caret_color, CaretColor)
COMPUTED_STYLE_PROP(clear, Clear)
COMPUTED_STYLE_PROP(clip, Clip)
COMPUTED_STYLE_PROP(color, Color)

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

@ -1142,13 +1142,16 @@ SetComplexColor(const nsCSSValue& aValue,
aResult = StyleComplexColor::CurrentColor();
} else if (unit == eCSSUnit_ComplexColor) {
aResult = aValue.GetStyleComplexColorValue();
} else if (unit == eCSSUnit_Auto) {
aResult = StyleComplexColor::Auto();
} else {
nscolor resultColor;
if (!SetColor(aValue, aParentColor.mColor, aPresContext,
nullptr, aResult.mColor, aConditions)) {
nullptr, resultColor, aConditions)) {
MOZ_ASSERT_UNREACHABLE("Unknown color value");
return;
}
aResult.mForegroundRatio = 0;
aResult = StyleComplexColor::FromColor(resultColor);
}
}
@ -5293,6 +5296,14 @@ nsRuleNode::ComputeUserInterfaceData(void* aStartStruct,
parentUI->mPointerEvents,
NS_STYLE_POINTER_EVENTS_AUTO);
// caret-color: auto, color, inherit
const nsCSSValue* caretColorValue = aRuleData->ValueForCaretColor();
SetComplexColor<eUnsetInherit>(*caretColorValue,
parentUI->mCaretColor,
StyleComplexColor::Auto(),
mPresContext,
ui->mCaretColor, conditions);
COMPUTE_END_INHERITED(UserInterface, ui)
}

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

@ -3974,6 +3974,7 @@ nsStyleUserInterface::nsStyleUserInterface(StyleStructContext aContext)
, mUserFocus(StyleUserFocus::None)
, mPointerEvents(NS_STYLE_POINTER_EVENTS_AUTO)
, mCursor(NS_STYLE_CURSOR_AUTO)
, mCaretColor(StyleComplexColor::Auto())
{
MOZ_COUNT_CTOR(nsStyleUserInterface);
}
@ -3985,6 +3986,7 @@ nsStyleUserInterface::nsStyleUserInterface(const nsStyleUserInterface& aSource)
, mPointerEvents(aSource.mPointerEvents)
, mCursor(aSource.mCursor)
, mCursorImages(aSource.mCursorImages)
, mCaretColor(aSource.mCaretColor)
{
MOZ_COUNT_CTOR(nsStyleUserInterface);
}
@ -4046,6 +4048,10 @@ nsStyleUserInterface::CalcDifference(const nsStyleUserInterface& aNewData) const
hint |= nsChangeHint_NeutralChange;
}
if (mCaretColor != aNewData.mCaretColor) {
hint |= nsChangeHint_RepaintFrame;
}
return hint;
}

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

@ -3400,6 +3400,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUserInterface
uint8_t mCursor; // [inherited] See nsStyleConsts.h
nsTArray<nsCursorImage> mCursorImages; // [inherited] images and coords
mozilla::StyleComplexColor mCaretColor; // [inherited]
inline uint8_t GetEffectivePointerEvents(nsIFrame* aFrame) const;
};

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

@ -2836,6 +2836,18 @@ var gCSSProperties = {
other_values: [ "bottom", "left", "right", "top-outside", "bottom-outside" ],
invalid_values: []
},
"caret-color": {
domProp: "caretColor",
inherited: true,
type: CSS_TYPE_LONGHAND,
prerequisites: { "color": "black" },
// Though "auto" is an independent computed-value time keyword value,
// it is not distinguishable from currentcolor because getComputedStyle
// always returns used value for <color>.
initial_values: [ "auto", "currentcolor", "black", "rgb(0,0,0)" ],
other_values: [ "green", "transparent", "rgba(128,128,128,.5)", "#123" ],
invalid_values: [ "#0", "#00", "#00000", "cc00ff" ]
},
"clear": {
domProp: "clear",
inherited: false,

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

@ -129,6 +129,9 @@ var supported_properties = {
"bottom": [ test_length_transition, test_percent_transition,
test_length_percent_calc_transition,
test_length_unclamped, test_percent_unclamped ],
"caret-color": [ test_color_transition,
test_true_currentcolor_transition,
test_auto_color_transition ],
"clip": [ test_rect_transition ],
"clip-path": [ test_clip_path_transition ],
"color": [ test_color_transition,
@ -1379,6 +1382,21 @@ function test_true_currentcolor_transition(prop, get_color=(x => x), is_shorthan
div.style.removeProperty("color");
}
function test_auto_color_transition(prop, get_color=(x => x), is_shorthand=false) {
const msg_prefix = `color-valued property ${prop}: `;
const test_color = "rgb(51, 102, 153)";
div.style.setProperty("transition-property", "none", "");
div.style.setProperty(prop, "auto", "");
let used_value_of_auto = get_color(cs.getPropertyValue(prop));
isnot(used_value_of_auto, test_color,
msg_prefix + "ensure used auto value is different than our test color");
div.style.setProperty("transition-property", prop, "");
div.style.setProperty(prop, test_color, "");
is(get_color(cs.getPropertyValue(prop)), test_color,
msg_prefix + "not interpolatable between auto and rgb color");
}
function get_color_from_shorthand_value(value) {
var m = value.match(/rgba?\([^, ]*, [^, ]*, [^, ]*(?:, [^, ]*)?\)/);
isnot(m, null, "shorthand property value should contain color");

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

@ -8,6 +8,7 @@ user_pref("gfx.color_management.force_srgb", true);
user_pref("gfx.logging.level", 1);
user_pref("browser.dom.window.dump.enabled", true);
user_pref("ui.caretBlinkTime", -1);
user_pref("ui.caretWidth", 1);
user_pref("dom.send_after_paint_to_content", true);
// no slow script dialogs
user_pref("dom.max_script_run_time", 0);

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

@ -6,9 +6,7 @@ package org.mozilla.gecko.home;
import android.content.Context;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
@ -123,10 +121,6 @@ public abstract class CombinedHistoryItem extends RecyclerView.ViewHolder {
nameView.setTextColor(ContextCompat.getColor(context, isCollapsed ? R.color.tabs_tray_icon_grey : R.color.placeholder_active_grey));
if (client.tabs.size() > 0) {
deviceExpanded.setImageResource(isCollapsed ? R.drawable.home_group_collapsed : R.drawable.arrow_down);
Drawable expandedDrawable = deviceExpanded.getDrawable();
if (expandedDrawable != null) {
DrawableCompat.setAutoMirrored(expandedDrawable, true);
}
}
}
}

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

@ -10,8 +10,6 @@ import java.util.concurrent.Future;
import android.content.Context;
import android.database.Cursor;
import android.support.v4.app.ActivityCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.TextViewCompat;
import android.text.TextUtils;
@ -167,9 +165,6 @@ public class TwoLinePageRow extends LinearLayout
}
mSwitchToTabIconId = iconId;
if (mSwitchToTabIconId != 0) {
DrawableCompat.setAutoMirrored(ActivityCompat.getDrawable(getContext(), mSwitchToTabIconId), true);
}
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(mUrl, mSwitchToTabIconId, 0, 0, 0);
}

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

@ -10,7 +10,6 @@ import org.mozilla.gecko.widget.themed.ThemedImageButton;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.util.AttributeSet;
public class MenuItemActionBar extends ThemedImageButton
@ -47,10 +46,6 @@ public class MenuItemActionBar extends ThemedImageButton
setVisibility(VISIBLE);
setImageDrawable(icon);
}
icon = getDrawable();
if (icon != null) {
DrawableCompat.setAutoMirrored(icon, true);
}
}
void setIcon(int icon) {

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

@ -11,7 +11,6 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.widget.TextViewCompat;
import android.util.AttributeSet;
import android.widget.TextView;
@ -53,8 +52,6 @@ public class MenuItemDefault extends TextView
mState = res.getDrawable(R.drawable.menu_item_state).mutate();
mState.setBounds(stateIconBounds);
// Support RTL
DrawableCompat.setAutoMirrored(mState, true);
if (sIconBounds == null) {
int iconSize = res.getDimensionPixelSize(R.dimen.menu_item_icon);
@ -118,9 +115,8 @@ public class MenuItemDefault extends TextView
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
if (mIcon != null) {
if (mIcon != null)
mIcon.setAlpha(enabled ? 255 : 99);
}
if (mState != null)
mState.setAlpha(enabled ? 255 : 99);

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

@ -8,10 +8,7 @@ package org.mozilla.gecko.preferences;
import org.mozilla.gecko.R;
import android.content.Context;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
class AlignRightLinkPreference extends LinkPreference {
@ -24,11 +21,4 @@ class AlignRightLinkPreference extends LinkPreference {
super(context, attrs, defStyle);
setLayoutResource(R.layout.preference_rightalign_icon);
}
@Override
protected void onBindView(View view) {
super.onBindView(view);
ImageView imageView = (ImageView) view.findViewById(R.id.menu_icon_more);
DrawableCompat.setAutoMirrored(imageView.getDrawable(), true);
}
}

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

@ -13,7 +13,6 @@ import android.graphics.drawable.Drawable;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.TextViewCompat;
import android.view.LayoutInflater;
@ -85,10 +84,9 @@ public class PromptListAdapter extends ArrayAdapter<PromptListItem> {
return VIEW_TYPE_COUNT;
}
private Drawable getMoreDrawable(Context context) {
private Drawable getMoreDrawable(Resources res) {
if (mMoreDrawable == null) {
mMoreDrawable = ContextCompat.getDrawable(context, R.drawable.menu_item_more);
DrawableCompat.setAutoMirrored(mMoreDrawable, true);
mMoreDrawable = res.getDrawable(R.drawable.menu_item_more);
}
return mMoreDrawable;
}
@ -127,7 +125,7 @@ public class PromptListAdapter extends ArrayAdapter<PromptListItem> {
Drawable moreDrawable = null;
if (item.isParent) {
moreDrawable = getMoreDrawable(getContext());
moreDrawable = getMoreDrawable(res);
}
if (d != null || moreDrawable != null) {

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

@ -10,7 +10,6 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.ViewGroup;
@ -34,8 +33,6 @@ public class TabPanelBackButton extends ImageButton {
if (divider != null) {
dividerWidth = divider.getIntrinsicWidth();
}
// Support RTL
DrawableCompat.setAutoMirrored(getDrawable(), true);
}
@Override

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

@ -21,7 +21,6 @@ import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.View;
@ -51,8 +50,6 @@ abstract class BrowserToolbarPhoneBase extends BrowserToolbar {
// This will clip the translating edge's image at 60% of its width
urlBarTranslatingEdge.getDrawable().setLevel(6000);
// Support RTL
DrawableCompat.setAutoMirrored(urlBarTranslatingEdge.getDrawable(), true);
editCancel = (ThemedImageView) findViewById(R.id.edit_cancel);

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

@ -17,7 +17,6 @@ import android.graphics.Path;
import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
@ -44,10 +43,6 @@ public class ShapedButton extends ThemedImageButton
mCanvasDelegate = new CanvasDelegate(this, Mode.DST_IN, paint);
setWillNotDraw(false);
Drawable drawable = getDrawable();
if (drawable != null) {
DrawableCompat.setAutoMirrored(drawable, true);
}
}
@Override

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

@ -17,7 +17,7 @@
package org.mozilla.gecko.toolbar;
import android.support.v4.content.ContextCompat;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.R;
import org.mozilla.gecko.widget.themed.ThemedImageView;
import org.mozilla.gecko.util.WeakReferenceHandler;
@ -30,11 +30,9 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
/**
* Progress view used for page loads.
@ -88,7 +86,6 @@ public class ToolbarProgressView extends ThemedImageView {
@Override
public void onDraw(Canvas canvas) {
final Drawable d = getDrawable();
DrawableCompat.setAutoMirrored(d, true);
d.setBounds(mBounds.getBounds());
d.draw(canvas);
}

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

После

Ширина:  |  Высота:  |  Размер: 268 B

Двоичные данные
mobile/android/base/resources/drawable-ldrtl-hdpi/ic_menu_back.png Normal file

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

После

Ширина:  |  Высота:  |  Размер: 288 B

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

После

Ширина:  |  Высота:  |  Размер: 289 B

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

После

Ширина:  |  Высота:  |  Размер: 109 B

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

После

Ширина:  |  Высота:  |  Размер: 451 B

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

После

Ширина:  |  Высота:  |  Размер: 351 B

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

После

Ширина:  |  Высота:  |  Размер: 468 B

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

После

Ширина:  |  Высота:  |  Размер: 393 B

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

После

Ширина:  |  Высота:  |  Размер: 598 B

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

После

Ширина:  |  Высота:  |  Размер: 544 B

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

После

Ширина:  |  Высота:  |  Размер: 842 B

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

После

Ширина:  |  Высота:  |  Размер: 240 B

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

После

Ширина:  |  Высота:  |  Размер: 365 B

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

После

Ширина:  |  Высота:  |  Размер: 357 B

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

После

Ширина:  |  Высота:  |  Размер: 123 B

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

После

Ширина:  |  Высота:  |  Размер: 584 B

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

После

Ширина:  |  Высота:  |  Размер: 347 B

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

После

Ширина:  |  Высота:  |  Размер: 808 B

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

@ -631,7 +631,11 @@ pref("apz.axis_lock.breakout_threshold", "0.03125"); // 1/32 inches
pref("apz.axis_lock.breakout_angle", "0.3926991"); // PI / 8 (22.5 degrees)
pref("apz.axis_lock.direct_pan_angle", "1.047197"); // PI / 3 (60 degrees)
pref("apz.content_response_timeout", 400);
#ifdef NIGHTLY_BUILD
pref("apz.drag.enabled", true);
#else
pref("apz.drag.enabled", false);
#endif
pref("apz.danger_zone_x", 50);
pref("apz.danger_zone_y", 100);
pref("apz.disable_for_scroll_linked_effects", false);

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

@ -6,12 +6,25 @@ XPCOMUtils.defineLazyModuleGetter(this, "ExtensionStorage",
"resource://gre/modules/ExtensionStorage.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionStorageSync",
"resource://gre/modules/ExtensionStorageSync.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AddonManagerPrivate",
"resource://gre/modules/AddonManager.jsm");
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
var {
EventManager,
ExtensionError,
} = ExtensionUtils;
function enforceNoTemporaryAddon(extensionId) {
const EXCEPTION_MESSAGE =
"The storage API will not work with a temporary addon ID. " +
"Please add an explicit addon ID to your manifest. " +
"For more information see https://bugzil.la/1323228.";
if (AddonManagerPrivate.isTemporaryInstallID(extensionId)) {
throw new ExtensionError(EXCEPTION_MESSAGE);
}
}
function storageApiFactory(context) {
let {extension} = context;
return {
@ -33,15 +46,19 @@ function storageApiFactory(context) {
sync: {
get: function(spec) {
enforceNoTemporaryAddon(extension.id);
return ExtensionStorageSync.get(extension, spec, context);
},
set: function(items) {
enforceNoTemporaryAddon(extension.id);
return ExtensionStorageSync.set(extension, items, context);
},
remove: function(keys) {
enforceNoTemporaryAddon(extension.id);
return ExtensionStorageSync.remove(extension, keys, context);
},
clear: function() {
enforceNoTemporaryAddon(extension.id);
return ExtensionStorageSync.clear(extension, context);
},
},

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

@ -5,6 +5,10 @@
const STORAGE_SYNC_PREF = "webextensions.storage.sync.enabled";
Cu.import("resource://gre/modules/Preferences.jsm");
add_task(function* setup() {
yield ExtensionTestUtils.startAddonManager();
});
/**
* Utility function to ensure that all supported APIs for getting are
* tested.
@ -332,3 +336,34 @@ add_task(function* test_backgroundScript() {
Preferences.reset(STORAGE_SYNC_PREF);
yield extension.unload();
});
add_task(function* test_storage_requires_real_id() {
async function backgroundScript() {
const EXCEPTION_MESSAGE =
"The storage API is not available with a temporary addon ID. " +
"Please add an explicit addon ID to your manifest. " +
"For more information see https://bugzil.la/1323228.";
await browser.test.assertRejects(browser.storage.sync.set({"foo": "bar"}),
EXCEPTION_MESSAGE);
browser.test.notifyPass("exception correct");
}
let extensionData = {
background: `(${backgroundScript})(${checkGetImpl})`,
manifest: {
permissions: ["storage"],
},
useAddonManager: "temporary",
};
Preferences.set(STORAGE_SYNC_PREF, true);
let extension = ExtensionTestUtils.loadExtension(extensionData);
yield extension.startup();
yield extension.awaitFinish("exception correct");
Preferences.reset(STORAGE_SYNC_PREF);
yield extension.unload();
});

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

@ -206,6 +206,7 @@ void
nsFormFillController::NodeWillBeDestroyed(const nsINode* aNode)
{
mPwmgrInputs.Remove(aNode);
mAutofillInputs.Remove(aNode);
if (aNode == mListNode) {
mListNode = nullptr;
RevalidateDataList();
@ -220,7 +221,7 @@ nsFormFillController::MaybeRemoveMutationObserver(nsINode* aNode)
{
// Nodes being tracked in mPwmgrInputs will have their observers removed when
// they stop being tracked.
if (!mPwmgrInputs.Get(aNode)) {
if (!mPwmgrInputs.Get(aNode) && !mAutofillInputs.Get(aNode)) {
aNode->RemoveMutationObserver(this);
}
}
@ -294,6 +295,21 @@ nsFormFillController::MarkAsLoginManagerField(nsIDOMHTMLInputElement *aInput)
return NS_OK;
}
NS_IMETHODIMP
nsFormFillController::MarkAsAutofillField(nsIDOMHTMLInputElement *aInput)
{
/*
* Support other components implementing form autofill and handle autocomplete
* for the field.
*/
nsCOMPtr<nsINode> node = do_QueryInterface(aInput);
NS_ENSURE_STATE(node);
mAutofillInputs.Put(node, true);
node->AddMutationObserverUnlessExists(this);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
//// nsIAutoCompleteInput
@ -509,6 +525,14 @@ nsFormFillController::GetSearchCount(uint32_t *aSearchCount)
NS_IMETHODIMP
nsFormFillController::GetSearchAt(uint32_t index, nsACString & _retval)
{
if (mAutofillInputs.Get(mFocusedInputNode)) {
nsCOMPtr<nsIAutoCompleteSearch> profileSearch = do_GetService("@mozilla.org/autocomplete/search;1?name=autofill-profiles");
if (profileSearch) {
_retval.AssignLiteral("autofill-profiles");
return NS_OK;
}
}
_retval.AssignLiteral("form-history");
return NS_OK;
}
@ -908,6 +932,18 @@ nsFormFillController::RemoveForDocument(nsIDocument* aDoc)
iter.Remove();
}
}
for (auto iter = mAutofillInputs.Iter(); !iter.Done(); iter.Next()) {
const nsINode* key = iter.Key();
if (key && (!aDoc || key->OwnerDoc() == aDoc)) {
// mFocusedInputNode's observer is tracked separately, so don't remove it
// here.
if (key != mFocusedInputNode) {
const_cast<nsINode*>(key)->RemoveMutationObserver(this);
}
iter.Remove();
}
}
}
void

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

@ -111,6 +111,7 @@ protected:
nsString mLastSearchString;
nsDataHashtable<nsPtrHashKey<const nsINode>, bool> mPwmgrInputs;
nsDataHashtable<nsPtrHashKey<const nsINode>, bool> mAutofillInputs;
uint32_t mTimeout;
uint32_t mMinResultsForPopup;

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

@ -43,4 +43,12 @@ interface nsIFormFillController : nsISupports
* @param aInput - The HTML <input> element to tag
*/
void markAsLoginManagerField(in nsIDOMHTMLInputElement aInput);
/*
* Mark the specified <input> element as being managed by a form autofill component.
* Autocomplete requests will be handed off to the autofill component.
*
* @param aInput - The HTML <input> element to mark
*/
void markAsAutofillField(in nsIDOMHTMLInputElement aInput);
};

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

@ -3071,6 +3071,23 @@ this.AddonManagerPrivate = {
getUpgradeListener: function(aId) {
return AddonManagerInternal.upgradeListeners.get(aId);
},
/**
* Predicate that returns true if we think the given extension ID
* might have been generated by XPIProvider.
*/
isTemporaryInstallID: function(extensionId) {
if (!gStarted)
throw Components.Exception("AddonManager is not initialized",
Cr.NS_ERROR_NOT_INITIALIZED);
if (!extensionId || typeof extensionId != "string")
throw Components.Exception("extensionId must be a string",
Cr.NS_ERROR_INVALID_ARG);
return AddonManagerInternal._getProviderByName("XPIProvider")
.isTemporaryInstallID(extensionId);
},
};
/**

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

@ -1364,6 +1364,8 @@ function defineSyncGUID(aAddon) {
});
}
const TEMPORARY_ADDON_SUFFIX = "@temporary-addon";
// Generate a unique ID based on the path to this temporary add-on location.
function generateTemporaryInstallID(aFile) {
const hasher = Cc["@mozilla.org/security/hash;1"]
@ -1374,7 +1376,7 @@ function generateTemporaryInstallID(aFile) {
const sess = TEMP_INSTALL_ID_GEN_SESSION;
hasher.update(sess, sess.length);
hasher.update(data, data.length);
let id = `${getHashStringForCrypto(hasher)}@temporary-addon`;
let id = `${getHashStringForCrypto(hasher)}${TEMPORARY_ADDON_SUFFIX}`;
logger.info(`Generated temp id ${id} (${sess.join("")}) for ${aFile.path}`);
return id;
}
@ -3968,6 +3970,11 @@ this.XPIProvider = {
return true;
},
// Identify temporary install IDs.
isTemporaryInstallID: function(id) {
return id.endsWith(TEMPORARY_ADDON_SUFFIX);
},
/**
* Called to get an AddonInstall to download and install an add-on from a URL.
*